如何在Haskell函数中使用类型类?

如何在Haskell函数中使用类型类?,haskell,typeclass,type-declaration,Haskell,Typeclass,Type Declaration,我现在试着用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` (lis

我现在试着用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
。我非常感谢您的建议。

问题出在这里:

avg l = ((foldr (+) 0 l) `div` (listlen l))
listlen :: [a] -> Int
listlen [] = 0
listlen (x:xs) = 1 + listlen xs
div
是在
Integral
s上定义的,而不仅仅是
Num
s。另外,
div
floors将显示结果。正常除法是
(/)
,它是在
分数上定义的

另外(更直接地)从这里:

avg l = ((foldr (+) 0 l) `div` (listlen l))
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)

您测试过这个解决方案吗?我刚刚尝试了固定的代码,但仍然遇到类似的错误。
length
返回一个
Int
。我想你还没有学到关于测试的知识哦,天哪;;;