【问题标题】:A more haskellian way to write this recursion?编写此递归的更哈斯克尔方式?
【发布时间】:2015-09-15 02:58:39
【问题描述】:

我写了一个代码来计算两个无穷级数的商的系数,使用归约,如下:

main :: Int -> PInt
main 0 = 0
main n = cancel x3
    where
    x1 = someOtherFunction
    x2 = expression involving x1
    x3 = x2 - (foldr 
        (\y z -> z + (someOtherFunction y) * (main (n - y))) 0 [1..(n - 1)])

(我定义了一个叫PInt的数据,它是Num和Fractional的一个实例,还有一个辅助函数“cancel”来进行归约。)我的问题是x3中fold中的表达式:好像不是非常有效,因为它必须计算每个主 k 值以获得较低的 k 值。

我在想也许我可以使用诸如

之类的实现
fib = 1 : 1 : zipWith (+) fib (tail fib)

对于斐波那契数计算上面的递归,效率更高。不幸的是,我不知道从哪里开始。

提前感谢您的帮助。

附:代码需要大量时间来计算 20 处的值,哪种行为似乎意味着时间呈指数增长?

【问题讨论】:

  • codereview.stackexchange.com 是要求对已经运行的代码进行审查的更好地方。
  • 感谢您的信息。
  • (也许你可以简单地memoizemain。)
  • @Mauris 实际上我使用了 memo1,我省略了显示,因为在这种情况下它不是很有用:没有太大区别。还是您建议我使用某种 memo_n 递归地记住它??
  • 两种可能的解释:系数增长得如此之快以至于超过了重新计算早期系数的成本,或者你做错了记忆(不难)。

标签: haskell recursion


【解决方案1】:

函数的内容如下:

main 0 = 0
main n = f [main n' | n' <- [0..n-1]]

您已经告诉我们一些关于f 的信息,但对于f 本身来说还不够。即便如此,正如你所说,我们可以通过攻击递归调用来记忆一些东西:

mains = 0 : map f (inits mains)
main = (mains!!)

事实上,在您的代码中,您对f 的特化恰好从不查看它提供的列表的头部(并且您通过计算[1..n-1] 而不是[0..n-1] 来内化它)。如果我们愿意,我们可以通过以下方式将这个问题转至mains

mains = 0 : map (f' . drop 1) (inits mains)
-- corresponds to the specification:
-- main 0 = 0
-- main n = f' [main n' | n' <- [1..n-1]]

虽然我认为将其留给f 可能实际上更干净。

【讨论】:

  • 感谢您的回答:这是我第一次听说 inits 及其用途。那么感谢这个很好的答案! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
相关资源
最近更新 更多