【问题标题】:Doing something on the final result of a recursive function, whithin the same function对递归函数的最终结果做一些事情,在同一个函数中
【发布时间】:2015-08-07 23:12:06
【问题描述】:

显示比解释更容易。我有这个小函数可以从基数 10 进行基数转换:

demode 0 _ = [] 
demode n b = m:(demode d b)
 where (d, m) = divMod n b

所以,如果我们想看看如何以 9 为基数写出 28,则将 28 9 = [1,3] 解调。 但是,当然,我们必须反转列表,使其看起来像 31。 这可以通过创建一个调用“demode”然后反转它的函数来轻松实现,但是 Haskell 非常酷,而且可能有一种更优雅的方式来表达“在最终情况下(demode 0 _),追加所有内容到一个列表,然后反转该列表”。

请注意,基本转换只是我用来说明问题的一个示例,真正的问题是如何将最终转换应用于递归函数的最后一个结果。

【问题讨论】:

  • 与您的问题无关,但我认为您的demode 已损坏:demode 9 9 是什么? (顺便说一句,像这样的角落案例是很好的测试用例。)。
  • 使用外部函数调用demode 并返回反转结果怎么样?
  • demode 9 9 = [0 , 1] -> 10,不是吗?关于外部功能:我想到并在上面提到过。当然,对于这种情况,它很容易而且足够好,但在其他一些情况下,它会很有用。此外,改进你的 haskell 语法也不错。

标签: haskell recursion


【解决方案1】:

不。您唯一的希望是使用辅助函数。请注意,Haskell 确实 允许您在 where 子句中定义函数(至少现在是这样),因此在单独的顶层意义上不必是“单独的函数”定义。你基本上有两种选择:

添加一个累加器,最后做任何你想做的工作:

demode n b = w n [] where
    w 0 xn = reverse xn
    w n xn = w d (xn ++ [m]) where
        (d, m) = divMod n b

希望你能按照它的工作原理进行操作,但请注意,在这种情况下,你最好说

demode n b = w n [] where
    w 0 xn = xn
    w n xn = w d (m : xn) where
        (d, m) = divMod n b

它以相反的顺序构建列表并返回它。

将常规定义下推到辅助函数中,并将该函数包装在您想要的任何工作中:

demode n b = reverse (w n) where
    w 0 = []
    w n = m : w d where
        (d, m) = divMod n b

(在所有三个示例中,我都使用术语 w 作为“工人”的简写)。

这两种情况通常都可以从学习使用高阶函数进行递归中受益。

一般来说,在 Haskell 中尝试“在一个函数中做所有事情”有点糟糕; Haskell 风格是围绕将问题分成多个部分,解决具有单独功能的部分,并将结果功能组合在一起而构建的; 尤其是如果这些功能在其他地方也有用(这种情况发生的频率比你天真的预期的要多)。

【讨论】:

  • 谢谢!但是你是什么意思“Haskell 确实允许你在 where 子句中定义函数(至少现在)”,是否有计划在未来禁止它们?这让我害怕,我喜欢 where 子句的灵活性,它让一切变得更简洁、更容易。
  • @AsíMaullóJosetustra - 对此嗤之以鼻:research.microsoft.com/en-us/um/people/simonpj/papers/…,主要是。据推测,如果在where 子句中使用辅助函数的人数足够少,它最终也会被删除。
  • @jcast,当像 Simon Peyton Jones 那样熟练和经验丰富的人说类型系统太复杂而无法调试时,可能是这样。让泛化在 HM 中是免费的,但在 Glasgow Haskell 中,它很昂贵并且(因为范围类型变量可用)不值这个价。 Así,您不必担心 where 子句中的函数——它们会一直存在。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-05
  • 2017-10-13
  • 1970-01-01
相关资源
最近更新 更多