Haskell,函数组合中的“无法匹配预期类型”

时间:2013-11-09 17:24:40

标签: haskell

我正在尝试编写一个简单的函数,通过获取模数并检查是否为0来检查一个整数是否除以另一个整数。我的想法就像是

divides :: (Integral a) => a -> a -> Bool
divides = (==0) . (flip mod)

除非b除以b,否则b将为真。但是,此代码给出了错误

Couldn't match expected type `a -> Bool' with actual type `Bool'
Expected type: b0 -> a -> Bool
 Actual type: b0 -> Bool
In the first argument of `(.)', namely `(== 0)'
In the expression: (== 0) . mod

我真的不明白为什么这段代码不起作用。请赐教!

3 个答案:

答案 0 :(得分:6)

要点是,.只会为每个函数1提供参数,但flip mod需要两个参数。一个简单的解决方案是

(.:) = (.) . (.) -- the owl or boobs operator

divides = (0==) .: flip mod

其中.:

 (c -> d) -> (a -> b -> c) -> a -> b -> d

答案 1 :(得分:4)

要查看代码有什么问题,请手动eta-expand:

divides :: (Integral a) => a -> a -> Bool
divides = (==0) . (flip mod)
-- divides x = ((==0) . (flip mod)) x
--           = ((==0) $ flip mod x)
--           = flip mod x == 0

最后一行没有进行类型检查,因为(==) :: a -> a -> Bool,但divides x应该是a -> Bool类型,而不是Bool

更正代码的最简单方法是以更扩展的形式编写代码,例如:

divides :: (Integral a) => a -> a -> Bool
divides x = (==0) . (`mod` x)

如果你真的想把它写成eta-reduced,这就是它的样子:

divides :: (Integral a) => a -> a -> Bool
divides = ((==0).) . (flip mod)
-- divides x = ((==0).) $ (`mod` x)
--           = (==0) . (`mod x`)  

答案 2 :(得分:2)

看起来你期望.运算符延续flip mod对其结果采用两个参数的事实,即。你期待这个:

f :: a -> b -> c
g :: c -> d
g . f :: a -> b -> d

不幸的是,它不会那样工作。函数总是采用单个参数,并且通过具有返回函数的函数来“模拟”多个参数函数。例如,a -> b -> c可以读为a -> (b -> c)。因此会发生什么如下:

f :: a -> (b -> c)
g :: (b -> c) -> d
g . f :: a -> d

这就是为什么g(在你的情况下是(== 0))期望一个函数,而你的函数类型实际上是a -> Bool而不是a -> a -> Bool