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.
我真的不明白我做错了什么,有人能提供任何指导吗?感谢。
答案 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还会将严格记录编译为更加节省内存的结构。
子>