2015-01-11 152 views
0

我還在學習Haskell,我正在做一些練習,但我一直在困惑。所以我有一個叫做「novel」的函數,它的參數需要2個字符串和一個Int (novel :: (String, String, Int) -> String)。新的輸入/輸出必須如下所示:Haskell中的遞歸

> novel ("Rowling", "Harry Potter", 1998) 
"Harry Potter (Rowling, 1998)" 

這是我對我的小說的功能代碼作品如上解釋說:

novel :: (String, String, Int) -> String 
novel (author, book, year) = book ++ " (" ++ author ++ ", " ++ (show year) ++ ")" 

我試圖寫一個所謂的新功能,「舉「(cite :: [(String, String, Int)] -> String)。引用的輸入/輸出應如下所示:

> cite [("author1", "book1", year1), ("author2", "book2", year2), ("author3", "book3", year3)] 
"book1 (author1, year1) 
book2 (author2, year2) 
book3 (author3, year3)" 

我試圖用「小說,」遞歸,爲了得到所需的輸出,但我不知道如何去這件事。

我已經試過:

cite :: [(String, String, Int)] -> String    -- | Listed arguments 
cite [] = ""            -- | Base Case 
cite x:xs = [(novel (author, book, year)), (novel (author, book, year)), (novel (author, book, year))] 

這是誠實的,據我得到了。顯然,它不起作用,但我不確定在這裏做什麼。

+1

提示:查看['map'](http://hackage.haskell.org/package/base-4.7.0.2/docs/src/GHC-Base.html#map)獲取想法。 – bheklilr

+0

是否希望它返回在每個引用之間使用「\ n」的'String'(即'[Char]'),還是要返回'[String]'? – TheCriticalImperitive

+0

我不明白地圖如何幫助我。我對map的理解是,它需要一個函數和一個列表,並且可以用算術運算來處理該列表中的項目。 –

回答

5

也許這會給你一個良好的開端:

cite :: [(String, String, Int)] -> String 
cite [] = "" 
cite (x:xs) = undefined -- put your code that recursively calls cite in here, hint: use ++ and "\n\" 

模式匹配(x:xs)說這個,給我的第一個項目在列表x和列表xs的尾部。這將是一樣寫這:

cite xs' = let x = head xs' 
       xs = tail xs' 
      in undefined -- your code here 

甚至

cite xs' = undefined -- your code here 
    where 
     x = head xs' 
     xs = tail xs' 

希望幫助推你在正確的方向。

編輯:下面OP問如何做到這一點遞歸,是我原來的答覆:

你或許應該重新寫你的基本情況說cite [] = ""。它並沒有真正改變,但它有助於代碼的可讀性。

讓我們通過把啓動 「:T映象小說」 到ghci中,看看你會得到什麼:

> :t map novel 
map novel :: [([Char], [Char], Int)] -> [[Char]] 

,我們可以爲改寫:map novel :: [(String, String, Int)] -> [String]

如何?因爲map會將一種類型a轉換爲另一種類型b,並將其應用於列表中的每個項目。 map的第一個參數是帶有一個參數的任何函數。究竟是什麼novel做。

但是,這並沒有給我們你需要什麼,我們就結束了字符串,而不是字符串列表:

> cite [("author1", "book1", year1), ("author2", "book2", year2), ("author3", "book3", year3)] 
["book1 (author1, year1)","book2 (author2, year2)","book3 (author3, year3)"] 

你想它是一個單一的字符串由分離換行符「\ n」。是否有一個函數可以獲取一個字符串列表並將它們連接成一個字符串,但插入它們之間的分隔符?

首先讓我們來描述一下這樣的功能:String -> [String] -> String。接下來,我們將它卡入Hoogle,看看我們得到了什麼:https://www.haskell.org/hoogle/?hoogle=String+-%3E+%5BString%5D+-%3E+String

啊,第二個函數intercalate聽起來像我們需要的。它不僅適用於字符串,它適用於任何列表。它將如何工作?類似這樣的:

> import Data.List (intercalate) 
> intercalate "\n" ["List","Of","Strings"] 
"List\nOf\nStrings" 

所以,現在你可以結合插入和地圖來得到你在之後。我將把cite的定義交給你。

編輯:完全忘了,實際上有一個專門的功能。如果您只是在Hoogle中搜索[String] -> String,您會發現unlines

+0

雖然我試圖遞歸地做到這一點。我發現了一些我正在遵循的pdf文本,而且我正在爲遞歸進行一章,而映射就是下一篇。它告訴我要純粹遞歸地做這件事。它沒有說任何關於必須導入任何東西的東西。 –

+0

啊,如果你還沒有了解'map',那麼上面會介紹太多。看到我更新的答案。 – TheCriticalImperitive

+0

我不明白你的意思,「用++和」\ n \「。」我應該使用那裏的新功能。我必須在遞歸中使用小說。如果我不清楚,我很抱歉。感謝您抽出時間抽出寶貴的時間。 –

1

這樣做有一個相當簡單的方法。

首先,將地圖novel映射到給定列表的每個元素,然後使用Data.List.intersperse用換行填充空格。這是我的實現:

import Data.List (intersperse) 

cite :: [(String, String, Int)] -> String 
cite bs = intersperse '\n' (map novel bs) 

或者,在一個更優雅的自由點式:

cite = intersperse '\n' . map novel 

你也可以寫一個很好的,有效的遞歸函數:

cite []  = "" 
cite [x] = novel x 
cite (x:xs) = novel x ++ '\n' : cite xs 

在未來像這樣的問題,請記住函數,如mapfoldr - 這是Haskell和函數式編程中最重要的兩個部分。另外,你的模式匹配需要用括號括起來。