我是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)
答案 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
转换为Int
或Double
而烦恼。而像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)