Haskell的类型关联链令人费解

Alf*_*oli 2 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))
Run Code Online (Sandbox Code Playgroud)

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

谢谢,阿尔弗雷多

Jer*_*man 20

首先,listMean :: [a] -> Double说这listMean是一个将任何类型的列表a作为单个Double值的函数.

但是你依赖于能够应用于(+)list(foldl1 (+))的元素,这要求类型a是一个实例Num,这意味着你至少有:

listMean :: (Num a) => [a] -> b
Run Code Online (Sandbox Code Playgroud)

您还适用(/)于类型的值a,从结果foldl1操作.要做到这一点,a不仅必须是Num,而且必须是Fractional.将此要求应用于类型a会给出类型签名:

listMean :: (Fractional a) => [a] -> b
Run Code Online (Sandbox Code Playgroud)

现在,那是b什么?嗯,签名(/)(/) :: (Fractional a) => a -> a -> a.所以,结果也listMean必须是一个实例Fractional.此外,它必须Fractional与列表中包含的实例相同:b因此,类型实际上是类型a,并且listMean最常见的签名是:

listMean :: (Fractional a) => [a] -> a
Run Code Online (Sandbox Code Playgroud)

这正是编译器所推断的.如果你想专门为这个Double,你就必须更换两者的出现aDouble:

listMean :: [Double] -> Double
Run Code Online (Sandbox Code Playgroud)

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