Haskell:递归类型实现:RGB,颜色反转,颜色混合

huangapple go评论55阅读模式
英文:

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 !! 0cols !! 1cols !! 2] 

rgb (反转 绿色) =  cols = rgb 红色
                      [cols !! 01-cols !! 1cols !! 2] 

rgb (反转 蓝色) =  cols = rgb 红色
                     [cols !! 0cols !! 11-cols !! 2] 

rgb (反转 颜色) = rgb 颜色

rgb (混合 红色 绿色) =  cols1 = rgb 红色
                          cols2 = rgb 绿色
                          cols3 = rgb 蓝色
                          ave = (cols1 !! 0 + cols2 !! 1) / 2
                       [aveavecols3 !! 2] 

rgb (混合 绿色 红色) = rgb (混合 红色 绿色)

rgb (混合 绿色 蓝色) =  cols1 = rgb 红色
                           cols2 = rgb 绿色
                           cols3 = rgb 蓝色
                           ave = (cols1 !! 0 + cols2 !! 1) / 2
                        [aveavecols3 !! 2] 

rgb (混合 蓝色 绿色) = rgb (混合 绿色 蓝色)

rgb (混合 红色 蓝色) =  cols1 = rgb 红色
                         cols2 = rgb 绿色
                         cols3 = rgb 蓝色
                         ave = (cols1 !! 0 + cols2 !! 1) / 2
                       [aveavecols3 !! 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`。对所有这些进行模式匹配是不可能的,因为您的数据结构可以生成无限数量的值。实际上,例如&lt;code&gt;rgb (Invert (Invert (&amp;hellip; (Invert Red) &amp;hellip;)))&lt;/code&gt;具有任意数量的`Invert`。
您可以选择包装在`Invert`或`Mix`中的值,然后在这些值上调用`rgb`,并反转或混合最终产品,如下所示:
&lt;pre&gt;&lt;code&gt;rgb :: Color -&amp;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&lt;sub&gt;1&lt;/sub&gt; x&lt;sub&gt;2&lt;/sub&gt;) = zipWith mid (rgb x&lt;sub&gt;1&lt;/sub&gt;) (rgb x&lt;sub&gt;2&lt;/sub&gt;)
where
mid y&lt;sub&gt;1&lt;/sub&gt; y&lt;sub&gt;2&lt;/sub&gt; = (y&lt;sub&gt;1&lt;/sub&gt; + y&lt;sub&gt;2&lt;/sub&gt;) / 2&lt;/code&gt;&lt;/pre&gt;
对于样本数据,这样产生:
ghci&gt; rgb (Mix Red Green)
[0.5,0.5,0.0]
ghci&gt; rgb (Mix Red Green)
[0.5,0.5,0.0]
ghci&gt; rgb (Mix Red (Mix Red Green))
[0.75,0.25,0.0]
ghci&gt; rgb (Invert Red)
[0.0,1.0,1.0]
ghci&gt; rgb (Invert (Mix Red (Mix Red Green)))
[0.25,0.75,1.0]
ghci&gt; 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 &lt;code&gt;rgb (Invert (Invert (&amp;hellip; (Invert Red) &amp;hellip;)))&lt;/code&gt; 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:
&lt;pre&gt;&lt;code&gt;rgb :: Color -&amp;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&lt;sub&gt;1&lt;/sub&gt; x&lt;sub&gt;2&lt;/sub&gt;) = zipWith mid (rgb x&lt;sub&gt;1&lt;/sub&gt;) (rgb x&lt;sub&gt;2&lt;/sub&gt;)
where
mid y&lt;sub&gt;1&lt;/sub&gt; y&lt;sub&gt;2&lt;/sub&gt; = (y&lt;sub&gt;1&lt;/sub&gt; + y&lt;sub&gt;2&lt;/sub&gt;) / 2&lt;/code&gt;&lt;/pre&gt;
For the sample data, this then produces:
ghci&gt; rgb (Mix Red Green)
[0.5,0.5,0.0]
ghci&gt; rgb (Mix Red Green)
[0.5,0.5,0.0]
ghci&gt; rgb (Mix Red (Mix Red Green))
[0.75,0.25,0.0]
ghci&gt; rgb (Invert Red)
[0.0,1.0,1.0]
ghci&gt; rgb (Invert (Mix Red (Mix Red Green)))
[0.25,0.75,1.0]
ghci&gt; rgb (Mix (Invert Red) (Invert Green))
[0.5,0.5,1.0]
</details>

huangapple
  • 本文由 发表于 2023年5月28日 14:47:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76350278.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定