RGB到CMYK,Haskell

时间:2016-10-30 10:42:13

标签: haskell functional-programming

Haskell初学者(以及一般的编程新手),我正在尝试编写一个将RGB颜色值转换为CMYK的代码。我在这里搜索过以供参考,之后我设法写了这个:

rgb2cmyk :: Int Int Int -> (Float,Float,Float,Float)
rgb2cmyk r g b = ((w - (r/255))/w, (w - (g/255))/w, (w -(b/255))/w, 1 - w)
             where  w = max (r/255, g/255, b/255)

当尝试在GHCi中加载模块时,我得到以下内容:

‘Int’ is applied to too many type arguments
In the type signature for ‘rgb2cmyk’:
  rgb2cmyk :: Int Int Int -> (Float, Float, Float, Float)
Failed, modules loaded: none.

我真的不明白我做错了什么,有人能提供任何指导吗?感谢。

1 个答案:

答案 0 :(得分:3)

具有多个参数的Haskell函数在某种程度上有点奇怪(但是,在你已经习惯了,非常有用之后)。 rgb2cmyk r g b = ...实际上只是撰写lambda expression rgb2cmyk = \r -> \g -> \b -> ...的简短方法,即实际上这是三个函数的嵌套,每个函数只需一个参数。因此,这个函数的类型确实是

rgb2cmyk :: Int -> (Int -> (Int -> ...))

因为这种模式在Haskell中很常见,所以定义了解析规则,因此您可以省略这些括号。因此,您尝试定义的签名实际上是

rgb2cmyk :: Int -> Int -> Int -> (Float,Float,Float,Float)

或者,你也可以成功

rgb2cmyk :: (Int,Int,Int) -> (Float,Float,Float,Float)
rgb2cmyk (r,g,b) = ...

在这种情况下,rgb2cmyk只有单个参数,但它具有复合类型。我认为这对于这个特定的函数来说实际上比每个颜色的三个单独的参数更合理。

但是Int Int Int不是三个整数的复合类型,它意味着一些非常不同的东西:它将第一个Int解释为类型级函数,它被应用于另外两个Int。这没有意义,Int不是类型级函数。这就是编译器错误告诉你的。

事实上,您可能不应该使用元组,而是使用适当命名的记录类型:

data RGB = RGB {_RChannel, _GChannel, _BChannel :: !Int}
data CMYK = CMYK {_CChannel, _MChannel, _YChannel, _KChannel :: !Float}

在这里,!使各个频道严格:单独评估所有颜色频道并没有多大意义,并且效率更高一气呵成。如果打开-XUnboxStrictFields扩展名,GHC还会将严格记录编译为更加节省内存的结构。