Haskell划分数量

时间:2009-11-29 22:24:16

标签: haskell types division typeclass

我有一个问题,我想了解更多,以及如何避免。我有这个代码

len :: (Num r ) => [a] -> r
len [] = 0
len xs = 1 + len ( tail xs )

avg :: (Num t) => [t] -> Double
avg xs = ( sum xs ) / ( len xs )

会出现以下错误

len.hs:6:9:
    Couldn't match expected type `Double' against inferred type `t'
      `t' is a rigid type variable bound by
          the type signature for `avg' at len.hs:5:12
    In the expression: (sum xs) / (len xs)
    In the definition of `avg': avg xs = (sum xs) / (len xs)

现在,我知道这个错误(感谢irc.freenode.net #haskell)是除法功能的结果

(/) :: (Fractional a) => a -> a -> a

但是,我不知道该怎么做。我的avg函数签名应与除法运算符怪异无关(需要Fractional类型类)。所以,我认为克服这个问题的正确方法是通过强制转换为一种类型,即他们Fractional类型,但我不知道如何,或者即使这是正确的?有什么想法吗?

4 个答案:

答案 0 :(得分:7)

  

我的avg函数签名应该与除法运算符的怪癖无关

为什么?如果你想计算一堆整数的平均值,你必须在某个时刻进行除法,所以你必须将它们从整数转换为你选择的除法支持类型。仔细查看Num类(ghci中的:i Num)会发现avg类型存在一个问题:Num没有足够的方法 - 基本上足以添加,乘以减。我无法保证我提供给avg的号码可以转换为Double

如果输入无类型函数来计算平均值,Haskell会使用最通用的类​​型进行响应:

Prelude List> :type \x -> sum x / genericLength x
\x -> sum x / genericLength x :: (Fractional a) => [a] -> a

这是avg的正确类型。

您可能会注意到avg [1,2,3 :: Integer]给出了类型错误。您可以先将参数传递给toRationalfromIntegral,然后分别使用RealIntegral Integer个实例来解决这个问题。


关于表达式sum [1,2,3] / len [1,2,3]:像1这样的字面数字的类型为Num a => a,而fromInteger类型调用1/2的类型确实如此,但像Fractional a => a这样的表达式有一个更具体的:set -Wall类型,如果您要求该表达式的类型而不是将其打印出来,您可以看到它。

可能有用的东西是ghci中的{{1}},无论何时为您选择默认类型,它都会发出大量警告,从而提供最通用类型可能不再正确的线索。

答案 1 :(得分:5)

你过分约束平均类型。使用更通用的版本,avg ::(Fractional a)=> [a] - >一个

答案 2 :(得分:1)

hhm真正的问题是,如果它是一个整数类型,你想要转换为小数类型,但如果它是一个小数类型,你想不管它。

试试这个

fromRational ((sum xs) % (leng xs))

答案 3 :(得分:0)

我遇到过这个问题。我设法做的最好的是有两个平均函数:一个用于积分,一个用于小数:

avgInt :: (Integral i, Fractional f) => [i] -> f
avgInt xs = fromIntegral (sum xs) / fromIntegral (length xs)

avgFrac :: (Fractional f) => [f] -> f
avgFrac xs = sum xs / fromIntegral (length xs)