Haskell中的递归

时间:2015-01-11 04:24:43

标签: haskell recursion

我还在学习Haskell,而且我正在做一些练习,但是我还是一团糟。所以我有一个名为“novel”的函数,它需要2个字符串和一个Int (novel :: (String, String, Int) -> String)的论点。 Novel的输入/输出必须如下所示:

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

这是我的新颖功能的代码,如上所述:

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

我正在尝试编写一个名为“cite”(cite :: [(String, String, Int)] -> String)的新函数。 Cite的输入/输出应如下所示:

> 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))]

老实说,就我而言。显然,它不起作用,但我不知道该怎么做。

2 个答案:

答案 0 :(得分: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 map novel”放入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

答案 1 :(得分: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和函数式编程中最重要的两个部分。此外,您的模式匹配需要括在括号中。