Haskell的类型关联链令人费解

时间:2010-11-02 18:44:16

标签: haskell types

我正在玩一些Haskell代码。我已经定义了两个函数:

count :: [a] -> Int
count []     = 0
count (x:xs) = 1 + (count xs)

-- 03. Write a function that computes the mean of a list, i.e., the sum of all 
-- elements in the list divided by its length. (You may need to use the 
-- fromIntegralfunction to convert the length of the list from an integer 
-- into a floating-point number.)

-- I've guessed this type definition, but it's incorrect:
-- listMean :: [a] -> Double
-- The following is the same inferred by hgci
listMean :: (Fractional a) => [a] -> a
listMean lst = (foldl1 (+) lst)/(fromIntegral (count lst))

为什么[a] - >双重不正确?看来我给lst是一个类型a的通用列表,listMean返回一个Double。我做错了什么?

谢谢, 阿尔弗雷

1 个答案:

答案 0 :(得分:20)

首先,listMean :: [a] -> Double表示listMean是一个将任意类型a的列表添加到单个Double值的函数。

但您依赖于能够将(+)应用于列表(foldl1 (+))的元素,这要求类型aNum的实例,这意味着你至少有:

listMean :: (Num a) => [a] -> b

您还将(/)应用于a操作产生的foldl1类型的值。为此,a不仅必须是Num的实例,还必须是Fractional的实例。将此要求应用于类型a会给出类型签名:

listMean :: (Fractional a) => [a] -> b

现在,b是什么?好吧,(/)的签名是(/) :: (Fractional a) => a -> a -> a。因此,listMean的结果也必须是Fractional的实例。此外,它必须与列表中包含的Fractional的实例相同:因此,类型b实际上是类型a,而listMean是最常见的签名是:

listMean :: (Fractional a) => [a] -> a

这正是编译器所推断的。如果您想对Double专门设置此项,则必须将 a两个替换为Double

listMean :: [Double] -> Double

这是因为你没有任何操作符会将Fractional的任何实例强制转换为Double,因此(/)的输入和输出都必须是Double类型}。