2013-05-14 91 views
0

我試圖計算一個具有如下功能的諧波系列。但是有一個類型錯誤,不太確定它是什麼意思?另一個問題,爲什麼[5..1]會給出一個空列表?Haskell - 這個函數有什麼問題?

sumHR = foldr相似(+)0(\ X - >地圖(1 /)[1..X])

錯誤消息:

*** Expression  : foldr (+) 0 (\x -> map (1 /) (enumFromTo x 1)) 
*** Term   : \x -> map (1 /) (enumFromTo x 1)  
*** Type   : b -> [b]  
*** Does not match : [a]  
+0

對於您的其他問題,請參閱:[遞減範圍在Haskell(http://stackoverflow.com/questions/6806455 /遞減範圍在haskell) – hammar 2013-05-14 01:48:17

回答

6

錯誤是告訴你,你的代碼不是很好的類型,因此沒有意義。

您的功能:

sumHR = foldr (+) 0 (\x -> map (1/) [1..x]) 

考慮:

Prelude> :t foldr 
foldr :: (a -> b -> b) -> b -> [a] -> b 

所以對於這是真的,(+)是第一個參數,類型必須統一(a -> b -> bNum a => a -> a -> a統一到Num a => a -> a -> a)。

第二個參數給出類型的變量b,我們已經知道必須Num a => a。這很好,你提供0作爲第二個參數。

第三個參數必須與類型Num a => [a]同意。但是,你已經提供了一個功能的第二個參數:

Prelude> :t (\x -> map (1/) [1..x]) 
(\x -> map (1/) [1..x]) :: (Enum b, Fractional b) => b -> [b] 

除非你能證明編譯器的類型(Enum b, Fractional b) => b -> [b]怎麼能做出一樣Num a => [a]然後你被卡住。

你可能已經包換的功能,如:

sumHR x = foldr (+) 0 (map (1/) [1..x]) 
+0

謝謝,這個解釋一切! – wildplace 2013-05-14 12:55:06

4

是你試圖寫它點免費?如果是這樣,你需要使用的複合算.組成foldr (+) 0(\x -> map (1/) [1..x])

sumHR = foldr (+) 0 . (\x -> map (1/) [1..x]) 

,或者點充分:

sumHR x = foldr (+) 0 (map (1/) [1..x]) 

(順便說一句,爲了提高效率,你需要使用的foldrfoldl'代替)

+5

而不是'fold'(+)0'爲什麼不是'sum'? – 2013-05-14 04:10:49

+0

我喜歡你的答案以及提高點算子! – wildplace 2013-05-14 12:56:45

4

前面的回答解釋瞭如何修復與你顯然要簽名的功能;但是這並不是一個很好的方法來計算序列,因爲對於您請求的每個元素,它必須從頭開始。一個更爲有效的,一個在Haskell其實更容易,方法是計算一個懶惰的名單,表示整個序列。所以,在開始與

map (1/) [1..] 

(或者,也許更易讀,[ 1/i | i<-[1..] ]),則執行「的結果的每個元素是在所述給定清單中的所有前述元素的總和」。這就是所謂的掃描。因爲在列表的整個一面(而不僅僅是兩個元素,比如摺疊),它總是嚴格的,所以需要從左側完成。你可以寫

sumHR' :: Fractional x => [x] 
sumHR' = scanl (+) 0 [ 1/i | i<-[1..] ] 

或等價因爲無限的名單是不會爲空,

sumHR' = scanl1 (+) [ 1/i | i<-[1..] ]