2015-01-11 110 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和函数式编程中最重要的两个部分。另外,你的模式匹配需要用括号括起来。