哈斯克尔的新人在这里。我正在尝试更好地编写类型签名,这个简单的签名不想工作。我想知道为什么:
average :: Num a => [a] -> a
average ns = sum ns `div` length ns
平均值应该取任何数字并返回一些数字。但是我收到了错误
test.hs 11:27:
Couldn't match expected type 'a' with actual type 'Int'
'a' is a rigid type variable bound by
the type signature for average :: Num a => [a] -> a
at test.hs:10:12
Relevant bindings include
ns:: [a] (bound at test.hs:11:9)
average :: [a] -> a (bound at test.hs:11:1)
In the second argument of 'div' namely 'length ns'
In the expression: sum ns `div ` length ns
似乎说长度没有达到预期的水平。有人可以帮忙吗?
答案 0 :(得分:3)
好的,这将有效:
average :: Integral a => [a] -> a
average ns = sum ns `div` (fromIntegral $ length ns)
请注意div :: Integral a => a -> a -> a
所以您需要Integral a
而不仅仅是Num a
(没有分割)
因为length
会返回Int
,所以您需要fromIntegral
来解决它。
答案 1 :(得分:2)
div
的类型是Integral a => a -> a -> a
,这意味着它的两个参数必须属于同一类型。在这种情况下,第二个参数始终为Int
类型(length
的结果),但第一个参数的类型为a
。
此外,您正在尝试编写适用于任何类型Num
的函数,但div
仅适用于整数类型。如果你想支持"平均"积分值列表(结果也四舍五入为整数),你可以这样做:
average :: Integral a => [a] -> a
average ns = sum ns `div` fromIntegral (length ns)
fromIntegral
会将Int
长度转换为任何整数类型a
(可能是Int
,或类似Integer
)。
为避免舍入错误,您需要对小数类型使用小数除法:
average :: Fractional a => [a] -> a
average ns = sum ns / fromIntegral (length ns)
答案 2 :(得分:0)
其他答案很好地突出了Num
与Integral
在调用length
后使用强制转换的提议的问题。或者,您可以使用genericLength
中的Data.List
:
import Data.List
average :: Integral a => [a] -> a
average ns = sum ns `div` genericLength ns