Haskell 在递归函数的最终结果上做一些事情,在同一个函数中
说起来容易,解释起来难。我有一个很小的函数,可以从基数10进行基数转换:Haskell 在递归函数的最终结果上做一些事情,在同一个函数中,haskell,recursion,Haskell,Recursion,说起来容易,解释起来难。我有一个很小的函数,可以从基数10进行基数转换: demode 0 _ = [] demode n b = m:(demode d b) where (d, m) = divMod n b 所以,如果我们想知道如何在基9中写28,解调289=[1,3]。 但是,当然,我们必须颠倒列表,使它看起来像一个31。 这可以通过创建一个调用“demome”的函数来实现,然后将其结果反转,但是由于Haskell非常酷,因此可能有一种更优雅的方式来表示“在最终情况下(demome
demode 0 _ = []
demode n b = m:(demode d b)
where (d, m) = divMod n b
所以,如果我们想知道如何在基9中写28,解调289=[1,3]。
但是,当然,我们必须颠倒列表,使它看起来像一个31。
这可以通过创建一个调用“demome”的函数来实现,然后将其结果反转,但是由于Haskell非常酷,因此可能有一种更优雅的方式来表示“在最终情况下(demome 0),将所有内容附加到列表中,然后反转列表”
请注意,基本转换只是我用来说明问题的一个示例,真正的问题是如何将最终转换应用于递归函数的最后一个结果 没有。您唯一的希望是使用helper函数。请注意,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
作为“worker”的缩写)
这两种情况都可以从学习使用高阶函数进行递归中获益
总的来说,在Haskell中尝试“在一个函数中完成所有任务”有点不好;Haskell风格是围绕着将问题划分为多个部分,使用单独的函数解决问题,并将结果函数组合在一起而构建的;特别是如果这些函数在其他地方也有用的话(这种情况发生的频率比你想象的要高)。与你的问题无关,但我认为你的
demode
被破坏了:什么是demode 9
?(顺便说一句,像这样的角落案例是很好的测试案例)。使用调用demome
并返回相反结果的外部函数怎么样?demome 9=[0,1]>10,不是很好吗?关于外部功能:我想到了,我在上面提到过。当然,对于这种情况来说,这很简单,也足够好,但在其他一些情况下,它会很有用。另外,提高haskell语法也不坏。谢谢!但是“Haskell确实允许您在where子句中定义函数(至少现在是这样)”是什么意思呢?将来有没有计划禁止它们呢?这让我害怕,我喜欢where条款的灵活性,它让一切变得更干净、更容易。@AsímoullóJosetustra-主要是这样说的。想必如果在where
子句中使用帮助函数的人太少,那么它最终也会被删除。@jcast,当像西蒙·佩顿·琼斯这样技术娴熟、经验丰富的人说类型系统太复杂而无法调试时,很可能是这样。在HM中,Let泛化是免费的,但在格拉斯哥-哈斯克尔(Glasgow-Haskell)中,它很昂贵,而且(因为有作用域类型变量可用)不值得。正如我所说,您不必担心where
子句中的函数——它们就在这里。