英文:
Haskell: A recursive type implementation: RGB, color inversion, color mixing
问题
以下是您提供的代码的翻译部分:
我有一个递归的代数数据类型,用于表示颜色并混合/反转特定的RGB通道:
数据类型 Color = 红色 | 绿色 | 蓝色 | 混合 Color Color | 反转 Color
派生展示
rgb :: Color -> [Double]
rgb 红色= [1,0,0]
rgb 绿色= [0,1,0]
rgb 蓝色= [0,0,1]
rgb (反转 红色) = 让 cols = rgb 红色
在 [1-cols !! 0,cols !! 1,cols !! 2] 中
rgb (反转 绿色) = 让 cols = rgb 红色
在 [cols !! 0,1-cols !! 1,cols !! 2] 中
rgb (反转 蓝色) = 让 cols = rgb 红色
在 [cols !! 0,cols !! 1,1-cols !! 2] 中
rgb (反转 颜色) = rgb 颜色
rgb (混合 红色 绿色) = 让 cols1 = rgb 红色
cols2 = rgb 绿色
cols3 = rgb 蓝色
ave = (cols1 !! 0 + cols2 !! 1) / 2
在 [ave,ave,cols3 !! 2] 中
rgb (混合 绿色 红色) = rgb (混合 红色 绿色)
rgb (混合 绿色 蓝色) = 让 cols1 = rgb 红色
cols2 = rgb 绿色
cols3 = rgb 蓝色
ave = (cols1 !! 0 + cols2 !! 1) / 2
在 [ave,ave,cols3 !! 2] 中
rgb (混合 蓝色 绿色) = rgb (混合 绿色 蓝色)
rgb (混合 红色 蓝色) = 让 cols1 = rgb 红色
cols2 = rgb 绿色
cols3 = rgb 蓝色
ave = (cols1 !! 0 + cols2 !! 1) / 2
在 [ave,ave,cols3 !! 2] 中
rgb (混合 蓝色 红色) = rgb (混合 红色 蓝色)
当我在以下代码中运行代码时:
主 :: IO ()
main = 做
打印(rgb(混合红色绿色))
打印(rgb(混合红色绿色))
打印(rgb(混合红色(混合红色绿色)))
打印(rgb(反转红色))
打印(rgb(反转(混合红色(混合红色绿色))))
打印(rgb(混合(反转红色)(反转绿色)))
我得到了运行时异常:
[1.0,1.0,1.0]
[1.0,1.0,1.0]
*** Exception: Main.hs:(158,1)-(195,39): 函数rgb中的非尽事项模式
我在这里做错了什么?
(我刚刚开始学习Haskell代数数据类型,所以当然会犯错误。)
<details>
<summary>英文:</summary>
I have this recursive, algebraic data type for representing colors and mixing/inverting particular RGB channels:
data Color = Red | Green | Blue | Mix Color Color | Invert Color
deriving Show
rgb :: Color -> [Double]
rgb Red = [1,0,0]
rgb Green = [0,1,0]
rgb Blue = [0,0,1]
rgb (Invert Red) = let cols = rgb Red
in [1 - cols !! 0, cols !! 1, cols !! 2]
rgb (Invert Green) = let cols = rgb Red
in [cols !! 0, 1 - cols !! 1, cols !! 2]
rgb (Invert Blue) = let cols = rgb Red
in [cols !! 0, cols !! 1, 1 - cols !! 2]
rgb (Invert color) = rgb color
rgb (Mix Red Green) = let cols1 = rgb Red
cols2 = rgb Green
cols3 = rgb Blue
ave = (cols1 !! 0 + cols2 !! 1) / 2
in [ave, ave, cols3 !! 2]
rgb (Mix Green Red) = rgb (Mix Red Green)
rgb (Mix Green Blue) = let cols1 = rgb Red
cols2 = rgb Green
cols3 = rgb Blue
ave = (cols1 !! 0 + cols2 !! 1) / 2
in [ave, ave, cols3 !! 2]
rgb (Mix Blue Green) = rgb (Mix Green Blue)
rgb (Mix Red Blue) = let cols1 = rgb Red
cols2 = rgb Green
cols3 = rgb Blue
ave = (cols1 !! 0 + cols2 !! 1) / 2
in [ave, ave, cols3 !! 2]
rgb (Mix Blue Red) = rgb (Mix Red Blue)
When I run the code in
main :: IO ()
main = do
print (rgb (Mix Red Green))
print (rgb (Mix Red Green))
print (rgb (Mix Red (Mix Red Green)))
print (rgb (Invert Red))
print (rgb (Invert (Mix Red (Mix Red Green))))
print (rgb (Mix (Invert Red) (Invert Green)))
I get the runtime exception:
[1.0,1.0,1.0]
[1.0,1.0,1.0]
*** Exception: Main.hs:(158,1)-(195,39): Non-exhaustive patterns in function rgb
What am I doing wrong here?
(I just started with Haskell algebraic datatypes, so, of course, I make mistakes.)
</details>
# 答案1
**得分**: 5
对于`Mix`,您只匹配模式`Mix Red Green`,`Mix Blue Red`等,而不是`Mix (Invert Red) Green`等或`Mix (Mix Red Green) Red`。对所有这些进行模式匹配是不可能的,因为您的数据结构可以生成无限数量的值。实际上,例如<code>rgb (Invert (Invert (&hellip; (Invert Red) &hellip;)))</code>具有任意数量的`Invert`。
您可以选择包装在`Invert`或`Mix`中的值,然后在这些值上调用`rgb`,并反转或混合最终产品,如下所示:
<pre><code>rgb :: Color -&gt; [Double]
rgb Red = [1, 0, 0]
rgb Green = [0, 1, 0]
rgb Blue = [0, 0, 1]
rgb (Invert x) = map (1 -) (rgb x)
rgb (Mix x<sub>1</sub> x<sub>2</sub>) = zipWith mid (rgb x<sub>1</sub>) (rgb x<sub>2</sub>)
where
mid y<sub>1</sub> y<sub>2</sub> = (y<sub>1</sub> + y<sub>2</sub>) / 2</code></pre>
对于样本数据,这样产生:
ghci> rgb (Mix Red Green)
[0.5,0.5,0.0]
ghci> rgb (Mix Red Green)
[0.5,0.5,0.0]
ghci> rgb (Mix Red (Mix Red Green))
[0.75,0.25,0.0]
ghci> rgb (Invert Red)
[0.0,1.0,1.0]
ghci> rgb (Invert (Mix Red (Mix Red Green)))
[0.25,0.75,1.0]
ghci> rgb (Mix (Invert Red) (Invert Green))
[0.5,0.5,1.0]
<details>
<summary>英文:</summary>
For `Mix`, you only pattern match on `Mix Red Green`, `Mix Blue Red`, etc. Not on `Mix (Invert Red) Green`, etc. or `Mix (Mix Red Green) Red`. Making patterns for all these is impossible, since your data structure can produce an infinite amount of values. Indeed, for example <code>rgb (Invert (Invert (&hellip; (Invert Red) &hellip;)))</code> with an arbitrary number of `Invert`s.
You can pick the value(s) wrapped in `Invert` or `Mix` and then call `rgb` on these and invert or mix the end product, like:
<pre><code>rgb :: Color -&gt; [Double]
rgb Red = [1, 0, 0]
rgb Green = [0, 1, 0]
rgb Blue = [0, 0, 1]
rgb (Invert x) = map (1 -) (rgb x)
rgb (Mix x<sub>1</sub> x<sub>2</sub>) = zipWith mid (rgb x<sub>1</sub>) (rgb x<sub>2</sub>)
where
mid y<sub>1</sub> y<sub>2</sub> = (y<sub>1</sub> + y<sub>2</sub>) / 2</code></pre>
For the sample data, this then produces:
ghci> rgb (Mix Red Green)
[0.5,0.5,0.0]
ghci> rgb (Mix Red Green)
[0.5,0.5,0.0]
ghci> rgb (Mix Red (Mix Red Green))
[0.75,0.25,0.0]
ghci> rgb (Invert Red)
[0.0,1.0,1.0]
ghci> rgb (Invert (Mix Red (Mix Red Green)))
[0.25,0.75,1.0]
ghci> rgb (Mix (Invert Red) (Invert Green))
[0.5,0.5,1.0]
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论