【问题标题】:Writing a recursive function on lists in Haskell在 Haskell 中的列表上编写递归函数
【发布时间】:2011-08-21 10:04:46
【问题描述】:

我有以下问题:

定义函数

and, or :: [Bool] -> Bool

给出布尔列表的合取和析取。例如,

and [False, True] = False
or  [False, True] = True

在一个空列表上,and 给出Trueor 给出False;解释这些选择的原因。

我知道我可以回答,但不确定最有效的方式。任何帮助将不胜感激。

我的解决方案是这样的(但我认为它可能更有效):

and, or :: [Bool] -> Bool

and []             = True
and [True, True]   = True
and [False, False] = True
and [True, False]  = False

or []             = False
or [True, True]   = False
or [False, False] = False
or [True, False]  = True

【问题讨论】:

  • 是的,这是家庭作业@Don Stewart,我现在已将其标记为 :) 我知道如何执行该功能,这就是我所做的(我相信有一个更有效的这样做的方法 - 现在已经在上面概述了)。
  • 这不是 Haskell,但您可能对 How To Design Programs 感兴趣,它可以很好地指导您如何设计程序(就像迄今为止的两个答案所做的那样)。

标签: list haskell recursion functional-programming


【解决方案1】:

我试图用折叠来解决这个问题

and = foldl (&&) True
or = foldl (||) False

这将是一个简单的解决方案 - 但我认为一个更抽象的解决方案 并采用 [Bool] 和 &&s 这个列表的第一个元素和累加器 True 这个结果将是foldl 的下一个累加器。

你的 ε/2

【讨论】:

  • 使用foldr 可能会更好。这样您就可以免费短路,并且可以避免评估列表的整个脊椎。试试foldl (&&) True (False : undefined)foldr 看看有什么不同。
【解决方案2】:

以下是我的一些信息:

and [] = True
and (True : xs) = and xs
and (False : xs) = False

or [] = False
or (True : xs) = True
or (False : xs) = or xs

对不起,如果我破坏了这个问题的“作业”模式。

【讨论】:

  • 是的,你做到了。你刚刚完成了我给出的起点。为什么?
  • 我不知道..我是在昏迷时做的:)
【解决方案3】:

我建议使用模式匹配来剖析列表。从这些条件开始:

and [] = True
and (True : xs) = ...
and (False : xs) = ...

好的,对于一个空列表andTrue。如果一个列表以“True”开头,你如何确定完整列表的“真相”?您是否需要递归调用?如果你有一个“False”的头像呢?

or的情况类似,以or [] = False开头

请注意,当您从这些定义开始时,它们已经在真值上进行模式匹配,您甚至不需要使用 &&||

【讨论】:

  • 赞成,因为我很欣赏这种回答家庭作业问题的方式。
  • 我也是。 (我知道,这样的 cmets 在 SO 上不受欢迎)
【解决方案4】:

您必须采取的关键步骤是归纳思考。您当前的解决方案:

and :: [Bool] -> Bool

and []             = True
and [True, True]   = True
and [False, False] = True
and [True, False]  = False

列举了一些可能性,但它显然不适用于所有列表。那么如何编写一个适用于任何长度的列表呢?

在 Haskell 中,您通常可以通过拆分数据类型来编写函数。在这种情况下,列出。列表定义为:

data [a] = []
         | a : [a]

所以,列表有两种情况:要么是空列表,要么是一个带尾的元素。让我们开始编写你的 and 函数,以便它匹配列表的这两种情况:

and []     = True
and (a:as) = ...

因此,“基本情况”,即空列表,是True。但是对于只有一个元素和一些尾部的列表,我们应该怎么做呢?

好吧,我们在 Haskell 中已经有了 && 函数:

> True && True
True
> True && False
False
> False && True
False
> False && False
False

有趣!因此,&& 接受两个参数,并正确确定两个参数是否为真。我们目前有一个包含一个元素的列表和一个包含尾部的列表。同时,我们定义了 and 函数,它在应用于列表时会产生一个布尔值。

所以我们可以进行归纳步骤,并使用我们定义的函数and&& 二元运算符来完成我们的定义:

and []     = True
and (a:as) = a && (and as)

所以我们将列表的尾部评估为某个值(递归地),并使用&& 运算符将那个值与当前值结合起来,这就是我们编写的函数。

由列表的递归结构驱动的递归和归纳是在编程中学习的关键技术。如果你能写出这篇文章,你就向前迈出了一大步。

【讨论】:

  • 呃,除非我遗漏了什么,否则问题是请他解释and []or [] 的选择,而不是如何实现这些功能。
  • 他们还想以and, or :: [Bool] -> Bool的形式定义它
  • @luqui -- 重新阅读:在我看来,这个问题显然是在询问如何编写 andor,给出一些示例行为,并且 OP 卡在递归上,不?
  • 就教学法而言,是从递归开始还是像foldl这样使用HoF更有用?我首先学习了递归,但我开始认为另一种方式可能会更好。 (这里似乎 Maclunian 正在研究递归 def,所以它是学术性的,但仍然......)
  • @John L:嗯,你只有在手工做了一些递归之后才真正学会喜欢折叠,对吧?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-21
  • 2016-08-13
  • 1970-01-01
  • 2017-06-22
  • 1970-01-01
  • 2011-10-31
相关资源
最近更新 更多