我目前正在尝试通过Learn You A Haskell自学Haskell,所以为了测试自己我正在尝试编写一个带有数字列表并返回平均值的函数。
listlen :: [a] -> Int
listlen [] = 0
listlen (x:xs) = 1 + listlen xs
avg :: (Num a) => [a] -> a
avg [] = error "Cannot average list of length 0"
avg l = ((foldr (+) 0 l) `div` (listlen l))
main = putStrLn (show (avg [1,2,3,4,5]))
但是,当我运行此代码时,收到此错误消息:
test.hs:7:10: error:
• Couldn't match expected type ‘a’ with actual type ‘Int’
‘a’ is a rigid type variable bound by
the type signature for:
avg :: forall a. Num a => [Int] -> a
at test.hs:5:8
• In the expression: ((foldr (+) 0 l) `div` (listlen l))
In an equation for ‘avg’:
avg l = ((foldr (+) 0 l) `div` (listlen l))
• Relevant bindings include
avg :: [Int] -> a (bound at test.hs:6:1)
我一直在修改签名,我能让它工作的唯一方法就是将类型变成实际类型,例如: avg :: [Int] -> Int
。我非常感谢任何建议。
答案 0 :(得分:2)
问题出在这里:
avg l = ((foldr (+) 0 l) `div` (listlen l))
div
定义在Integral
s上,而不只是Num
s。此外,div
对结果进行了落实。正常除法为(/)
,其定义为Fractional
s。
此处(更直接)来自:
listlen :: [a] -> Int
listlen [] = 0
listlen (x:xs) = 1 + listlen xs
listlen
会返回Int
,这会使div
的类型为Int -> Int -> Int
。
这应该有效:
listlen :: (Num n) => [a] -> n
listlen [] = 0
listlen (x:xs) = 1 + listlen xs
avg :: (Fractional a) => [a] -> a
avg [] = error "Cannot average list of length 0"
avg l = foldr (+) 0 l / listlen l
或者,使用Prelude
中的一些函数:
avg :: (Fractional a) => [a] -> a
avg [] = error "Cannot average list of length 0"
avg l = sum l / fromIntegral (length l)