2010-11-02 41 views
2

我正在玩一些Haskell代碼。我定義了兩個函數: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] - > Double不正確?看來,我給出了lst,這是一個類型a的通用列表,listMean返回一個Double。我究竟做錯了什麼?

感謝, 阿爾弗雷多

回答

20

首先,listMean :: [a] -> DoublelistMean是採取任何類型a的列表,以一個單一的Double值的函數。

但是你依靠的是能夠申請(+)到列表(foldl1 (+)),這需要該類型aNum一個實例,這意味着你必須至少的元素:

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

你也可以將(/)應用於由foldl1操作產生的a類型的值。爲此,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,你將不得不與Double更換兩個出現a

listMean :: [Double] -> Double 

這是因爲你在那裏有沒有運營商,這將迫使的Fractional任何實例爲Double,所以輸入和輸出到(/)必須是Double類型。

+1

+1,非常好的解釋。 – 2010-11-02 19:11:33

+0

完美!非常感謝你! – 2010-11-02 19:19:28