Haskell推断类型错误

时间:2016-04-16 18:20:14

标签: haskell type-inference

我是Haskell的新手,很好奇为什么会导致错误。

sumtest :: (Real a) => [a] -> a
sumtest [] = 0
sumtest (x:xs) = x + sumtest xs

avgFunction ::  (Integral a, Floating b) => [a] -> b
avgFunction a = sumtest a / length a

错误

ERROR file:code/test1.hs:114  - Inferred type is not general enough
*** Expression    : avgFunction
*** Expected type : (Integral a, Floating b) => [a] -> b
*** Inferred type : (Integral Int, Floating Int) => [Int] -> Int

-----每个接受的答案下面的工作代码----

sumtest :: (Num a) => [a] -> a
sumtest [] = 0
sumtest (x:xs) = x + sumtest xs

avgFunction ::  (Integral a, Floating b) => [a] -> b
avgFunction a = fromIntegral (sumtest a) / fromIntegral (length a)

2 个答案:

答案 0 :(得分:3)

  • sumtest a的结果类型为a。我们知道这是Integral类型。因此,可以划分的类型......
  • length a的结果类型为Int。这也是Integral类型。 (可能a是另一个。)

所以你试图划分两个数字,这两个数字都有无法划分的类型。嗯,那不行,是吗?

幸运的是,您可以转换数字。有些语言实际上是隐含地这样做(经常导致各种各样的破坏),但不是Haskell。好吧,但它肯定有功能来做到这一点! hoogle is your friend

avgFunction a = fromIntegral (sumtest a) / fromIntegral (length a)

<小时/> 不可否认, 有时候只需将每个length转换为IntDouble而烦恼。而像Python一样,一些保守的隐式转换确实看起来不太好太糟糕了。但任何类型的隐式转换都不适用于像Haskell这样的Hindley-Milner类型系统。

另一方面,这些限制实际上是不必要的。以下就足够了:

avgFunction ::  (Real a, Fractional b) => [a] -> b
avgFunction a = realToFrac (sumtest a) / realToFrac (length a)

这样,该函数还允许Double作为输入,而不仅仅是结果。 (也许它也更容易理解发生了什么。)

答案 1 :(得分:0)

(这实际上是对leftaroundabout's answer的评论/增强,但实际上需要的格式比注释允许的更多。)

模块Data.Function提供了一个函数on,它允许您指定一个函数来应用于每个函数的参数。在这种情况下,

avgFunction a = (sumtest a) ./ (length a)
                where (./) = (/) `on` fromIntegral

它实际上要长一点,但在本地定义的./运算符允许您通过抽象掉类型转换样板代码来集中算法的意义上可以说更清晰。

然后还有使用Control.Arrow的这个有趣的小宝石:

avgFunction = sum &&& length >>> uncurry ((/) `on` fromIntegral)