【问题标题】:Recursion in HaskellHaskell中的递归
【发布时间】:2015-01-11 22:00:46
【问题描述】:

我还在学习 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 :: [(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))]

老实说,据我所知。显然,它不起作用,但我不确定从这里开始做什么。

【问题讨论】:

  • 提示:查看map 的想法。
  • 您希望它返回在每次引用之间使用“\n”的String(即[Char]),还是返回[String]
  • 我不明白 map 在这里对我有什么帮助。我对 map 的理解是它需要一个函数和一个列表,您可以使用算术运算来操作该列表中的项目。
  • @TheCriticalImperitive 我没有返回列表。我正在返回一个字符串。它的返回方式与小说返回的方式相同。
  • @JoffreyBaratheon map 可以对列表项执行任何操作,而不仅仅是算术。 String 与 Haskell 中的 Chars 列表相同。事实上,String 类型只是 [Char] 的同义词。

标签: haskell recursion


【解决方案1】:

也许这会给你一个良好的开端:

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小说”放到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"

所以现在你可以结合 intercalate 和 map 来获得你想要的东西。我将把cite 的定义留给你。

编辑:完全忘记了,实际上有一个专门的功能。如果您只在 Hoogle 中搜索 [String] -> String,您会找到 unlines

【讨论】:

  • 我正在尝试以递归方式执行此操作。我发现了一些我正在关注的 pdf 文本,我正在讨论递归的一章,下一章是映射。它告诉我纯粹以递归方式执行此操作。它没有说必须导入任何东西。
  • 啊,如果你还没有了解map,那么上面的介绍太早了。请参阅我的更新答案。
  • 我不明白你的意思,“使用 ++ 和“\n\”。”我应该在那里使用小说功能。我必须在递归中使用小说。如果我不清楚,我很抱歉。感谢您为此抽出时间。
  • 一个非常常见的模式是这样的:recur (x:xs) = x ++ recur xs。所以取出第一项,对它做点什么,然后用列表的其余部分调用你的原始函数。
  • 我将在此评论的末尾留下答案。如果你真的卡住了看看。当您只画一个空白并且只想继续前进时,这可能会非常令人沮丧,所以如果您达到了这一点,答案是............:cite (x:xs) = novel x ++ "\n" ++ cite xs
【解决方案2】:

有一种相当简单的方法。

首先,将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 和函数式编程中最不可或缺的两个部分。此外,您的模式匹配需要用括号括起来。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 2011-09-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多