我在编写平均函数时出现此错误,如下所示
module Assignment where
average xs = sum xs / length xs
它到底想要什么? 是要求定义吗?我也提供了相同的错误
答案 0 :(得分:2)
你给出了一个定义,这不是问题所在。问题是Haskell无法在两个/
上应用Int
运算符,确实:
Prelude> (2 :: Int) / 3
<interactive>:1:1: error:
• No instance for (Fractional Int) arising from a use of ‘/’
• In the expression: (2 :: Int) / 3
In an equation for ‘it’: it = (2 :: Int) / 3
在终端中,我们要将2
与3
分开。我们强迫Haskell对Int
使用2
,并抱怨同样的事情。
原因是(/)
中定义了Fractional
:
class Num a => Fractional a where
(/) :: a -> a -> a
recip :: a -> a
fromRational :: Rational -> a
{-# MINIMAL fromRational, (recip | (/)) #-}
如您所见,该定义指出所有Fractional
都是Num
s,但并非所有Num
都是Fractional
s。这是合乎逻辑的。注意(/) :: a -> a -> a
的签名。如果我们在Int
s上使用它,它将具有签名(/) :: Int -> Int -> Int
。但这意味着2/3
将0
或1
(假设我们获得最接近的结果)。但是很开心。由于人们会因此而犯很多错误,Haskell库的设计者决定不使Int
成为Fractional
,但提供了div
函数积分划分。
当然这对我们没什么帮助。因为我们可能不希望结果首先是Int
。所以,我们可以做的是将length
结果转换到Fractional
。例如,我们可以使用fromIntegral :: (Integral a, Num b) => a -> b
函数执行此操作。因此我们可以将函数重新定义为:
average :: Fractional a => [a] -> a
average xs = sum xs / fromIntegral (length xs)
请注意,此处列表的元素的类型决定了平均输出的类型。该类型也需要Fractional
。所以我们不能处理Int
的列表,除非我们首先预处理列表(例如调用fromIntegral
到列表的元素)。如果列表包含整数元素,我们可以先计算总和,然后将其转换为Fractional
(从那时起结果会更精确)。然后我们可以将它定义为:
integrals_average :: (Integral a, Fractional b) => [a] -> b
integrals_average xs = fromIntegral (sum xs) / fromIntegral (length xs)