2014-01-22 137 views
4

我想獲得一個函數工作,使用foldl 來通過元組列表並從中創建一個字符串。 我正試圖創建一個類似的函數,它已經可以使用遞歸。Haskell使用foldl像遞歸

這裏是我想要編譯代碼:

citeBook :: (String, String, Integer) -> String 
citeBook (name, titl, date) = (titl ++ " (" ++ name ++ ", " ++ show date ++ ")\n") 

--Recursion function 
-- function must be called with putStr in order for newlines to work 
bibliography_rec :: [(String, String, Integer)] -> String 
bibliography_rec [] = "" 
bibliography_rec xs = (citeBook(head xs) ++ bibliography_rec (tail xs)) 

--foldl function 
bibliography_fold :: [(String, String, Integer)] -> String 
bibliography_fold [] = "" 
bibliography_fold (x:xs) = foldl (++) citeBook(x) xs --ERROR HERE 

因此,在所提供的代碼的最後一行,我想有與foldl 使用(++)作爲運營商爲了組合列表中的字符串。 我使用citeBook(x)作爲我的基本情況,因爲x將是從列表中取出的第一個元組 。請注意,citeBook(x)返回一個字符串。然後繼續使用列表xs摺疊 。

這是我收到的錯誤。我想我的參數類型與foldl不 與預期一致,但一切似乎還好我..

hw1.hs:28:34: 
    Couldn't match type `[a0]' 
        with `(String, String, Integer) -> String' 
    Expected type: ((String, String, Integer) -> String) 
        -> [a0] -> (String, String, Integer) -> String 
     Actual type: [a0] -> [a0] -> [a0] 
    In the first argument of `foldl', namely `(++)' 
    In the expression: foldl (++) citeBook (x) xs 
    In an equation for `bibliography_fold': 
     bibliography_fold (x : xs) = foldl (++) citeBook (x) xs 

hw1.hs:28:48: 
    Couldn't match expected type `[[a0]]' 
       with actual type `(String, String, Integer)' 
    In the third argument of `foldl', namely `(x)' 
    In the expression: foldl (++) citeBook (x) xs 
    In an equation for `bibliography_fold': 
     bibliography_fold (x : xs) = foldl (++) citeBook (x) xs 

hw1.hs:28:51: 
    Couldn't match expected type `(String, String, Integer)' 
       with actual type `[(String, String, Integer)]' 
    In the fourth argument of `foldl', namely `xs' 
    In the expression: foldl (++) citeBook (x) xs 
    In an equation for `bibliography_fold': 
     bibliography_fold (x : xs) = foldl (++) citeBook (x) xs 

我明白任何和所有的反饋。謝謝!

+2

是不是'bibliography_rec'只是'concatMap citeBook'? – bheklilr

+0

是的,發佈作爲答案。 – amnn

+0

bheklilr,我只是試過了,它確實工作,但我明確地試圖創建一個遞歸函數。我的問題是我試圖打印出一個列表,就像bibliography_rec一樣,但是使用foldl而不是遞歸 –

回答

4

您給foldl(++)功能,其型號爲String -> String -> String。但是,您正在摺疊的收藏集xs的類型爲[(String, String, Integer)],而不是[String]

你可以改變bibliography_fold

bibliography_fold :: [(String, String, Integer)] -> String 
bibliography_fold [] = "" 
bibliography_fold (x:xs) = foldl (++) (citeBook x) (map citeBook xs) 

,或者只是

bibliography_fold :: [(String, String, Integer)] -> String 
bibliography_fold xs = foldl (++) "" (map citeBook xs) 

但我是一個相對的小白在哈斯克爾自己,所以把我的編碼風格與一粒鹽。

此外,你需要寫(citeBook x)而不是citeBook(x),或者編譯器將假定citeBook(x)都參數foldl(糾正我,如果我錯了)。這有助於解釋爲什麼你得到的錯誤信息太奇怪了。

+0

我會強調'foldl(++)「」'版本更好,因爲它並不是特殊的空列表。 – hugomg

+0

謝謝jcarpenter!結果非常好。我自己是Haskell的noob。我想我對地圖功能不是很熟悉。看起來我會做一些研究。 –

+0

您也可以在不使用map函數的情況下編寫它,如下所示:'bibliography_fold xs = foldl(\ s t - > s ++ citeBook t)「」xs'。現在,累加器函數的類型爲'String - >(String,String,Integer) - > String',並且您正在摺疊'[(String,String,Integer)]''。 – jcarpenter2

3

你已經得到了你的答案,所以我將提供使用摺疊來解決這個問題的另一種方式:

bibliography_fold :: [(String, String, Integer)] -> String 
bibliography_fold = foldr ((++) . citeBook) "" 

有沒有地圖,沒有特殊情況下,它可以在點寫自由的風格。我鼓勵你在GHCi中解構這個表達式,並使用:info來檢查每個組件,以探索它是如何工作的。看看foldr,++,citeBook,(++) . citeBook的類型,看看你是否可以找出它的工作原理。您也可以查找foldr的源代碼。

+0

+1表示在此處使用foldr而不是fold1 – kosmikus