简体   繁体   English

Haskell的类型关联链令人费解

[英]Haskell's type associative chain is puzzling

I'm playing with some Haskell code. 我正在玩一些Haskell代码。 I've defined two functions: 我已经定义了两个函数:

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))

Why [a] -> Double is not correct? 为什么[a] - > Double不正确? It seems that I give lst that is a generic list of some type a and listMean returns a Double. 看来我给lst是一个类型a的通用列表,listMean返回一个Double。 What am I doing wrong? 我究竟做错了什么?

Thanks, Alfredo 谢谢,阿尔弗雷多

First of all, listMean :: [a] -> Double says that listMean is a function taking a list of any type a to a single Double value. 首先, listMean :: [a] -> Double表示listMean是一个函数, listMean任何类型a的列表转换为单个Double值。

But you rely on being able to apply (+) to the elements of the list ( foldl1 (+) ), which requires that the type a be an instance of Num , which means you have at least: 但是你依赖于能够将(+)应用于列表的元素( foldl1 (+) ),这要求类型aNum的实例,这意味着你至少有:

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

You also apply (/) to the value of type a that results from the foldl1 operation. 您还可以将(/)应用于由foldl1操作产生的类型a的值。 To do so, a must not only be an instance of Num , but of Fractional . 要做到这一点, a不仅必须的一个实例Num ,但Fractional Applying this requirement to the type a gives the type signature: 将此要求应用于类型a会给出类型签名:

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

Now, what of b ? 现在, b什么? Well, the signature for (/) is (/) :: (Fractional a) => a -> a -> a . 那么, (/)的签名是(/) :: (Fractional a) => a -> a -> a So, the result of listMean must also be an instance of Fractional . 因此, listMean的结果也必须是Fractional一个实例。 Further, it must be the same instance of Fractional as that contained in the list: type b is thus, in fact, type a , and listMean 's most general signature is: 此外,它必须与列表中包含的Fractional实例相同:因此,类型b实际上是类型a ,而listMean的最常见签名是:

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

This is exactly what the compiler inferred. 这正是编译器所推断的。 If you want to specialize this for Double , you would have to replace both occurrences of a with Double : 如果你想为Double专门化这个,你必须用Double替换两个出现的a

listMean :: [Double] -> Double

This is because you have no operator in there that will coerce any instance of Fractional into a Double , so both input and output to (/) must be of type Double . 这是因为你没有操作符将Fractional任何实例强制转换为Double ,因此(/)输入和输出必须是Double类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM