【问题标题】:Haskell List GenerationHaskell 列表生成
【发布时间】:2016-06-14 09:27:45
【问题描述】:

我发现了一个有趣的练习并尝试解决它。​​

它要求给定一个数字,它的数字应该以相反的顺序放在一个列表中。

现在,我几乎成功了:

lastDigit :: Integer -> Integer
lastDigit x = x `mod` 10

dropLastDigit :: Integer -> Integer
dropLastDigit x = (x - lastDigit x) `div` 10

numba2listInReverse :: Integer -> [Integer]
numba2listInReverse x = lastDigit x : numba2listInReverse (dropLastDigit x)

第一个函数只返回最后一个数字。第二个返回被剥夺了最后一位数字的数字。最后,最后一个函数生成列表。我的问题是我找不到 stop 递归的方法。查看输出:

Ok, modules loaded: Main.
*Main> dropLastDigit 123
12
*Main> numba2listInReverse 12345
[5,4,3,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0Interrupted.
*Main> 

即使数字用完,它也会继续在列表中添加零。如何解决?

【问题讨论】:

  • 测试0 以结束递归。 numba2listInReverse 0 = [] 之类的东西(还没有测试过,但这是基本思想)
  • 解决此问题的另一种方法是使用reverse $ show x
  • 我不得不提一下,有一个快速的单线涉及显示和反转,可以解决这个问题。另外,请注意您的输出是正确的,如果您认识到 1234 也可以写为 ..00001234。
  • dropLastDigit 可以写成dropLastDigit = flip div 10,不需要减法。
  • 感谢您的反馈,伙计们。现在,按顺序:1)我既不知道“显示”也不知道“反转”。但我会调查,听起来很有趣,谢谢!同样代表“翻转”。 2)如果我有一个像 0000123 这样的数字并且想把它全部放在列表中怎么办?检查零将排除初始零。

标签: list haskell recursion


【解决方案1】:

即使数字用完,它也会继续在列表中添加零。

那是因为你没有告诉 Haskell 在数字用完时停止。

你定义了一个递归函数。为了编写好的(阅读终止)递归函数,您需要一个停止条件:停止调用递归的条件。

您可以使用guard

numba2listInReverse :: 整数 -> [整数] numba2listInReverse x | x == 0 = [] |否则 = lastDigit x : numba2listInReverse (dropLastDigit x)

守卫用竖线字符(|)表示,后面跟着条件(如x == 0otherwise)。在条件之后,写入“赋值”运算符,然后是条件成立时要评估的表达式。条件会按照您编写它们的顺序进行测试。在重叠的情况下,成功的第一个条件将因此被“解雇”(可以这么说)。 otherwise 等于 True(您可以测试它,例如 ghci),因此如果上述守卫均未触发,则将始终触发。

如果因此将零 (0) 赋予 numba2listInReverse 函数,它将返回空列表(并且不再进行递归)。否则 (otherwise) 它将执行您定义的递归:“发出”最后一个数字作为列表中的第一个符号,然后是递归步骤。

注意:严格来说,Haskell 递归函数不一定需要停止条件:由于惰性求值,一些递归函数可以存在没有停止条件,例如定义一个包含“所有”素数的列表。


编辑:如果您想将0 映射到[0],您不能简单地将上面的代码修改为:

numba2listInReverse :: Integer -> [Integer]
numba2listInReverse x | x == 0 = [0]
                      | otherwise = lastDigit x : numba2listInReverse (dropLastDigit x)

确实,这会导致42 被映射到[2,4,0]。现在你可以通过引入一个辅助函数来解决这个问题,例如处理递归情况:

numba2listInReverse :: Integer -> [Integer]
numba2listInReverse x | x == 0 = [0]
                      | otherwise = help x
    where help x | x == 0 = []
                 | otherwise = lastDigit x : help (dropLastDigit x)

因此,您将非零情况留给help 函数。

【讨论】:

  • 感谢您详尽的回复。虽然我是一个 haskell 新人,但我知道守卫,不管你信不信,我完全想象了你的解决方案。但我放弃了它,因为我认为如果至少有一个数字为零,它就会停止。现在,我明白了我的错误,但问题仍然存在:如果数字 以零开头,则该零不会被放入列表中。您能否提出解决方法?
  • @MadHatter:如果您想将0 映射到[0],请查看更新的答案。 begins 是什么意思,Haskell 将042 解释为42,你无法知道用户是如何写数字的。
  • 我没有意识到这一点。很好,明白了..!
猜你喜欢
  • 1970-01-01
  • 2013-08-12
  • 2017-06-26
  • 1970-01-01
  • 1970-01-01
  • 2017-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多