【问题标题】:Adding a memoization with fix?添加带有修复的备忘录?
【发布时间】:2014-10-30 17:20:51
【问题描述】:

尝试解决计算满足某些谓词的组合(重复)计数的任务,例如元素的相等性总和为给定数:

countChange :: Integer -> [Integer] -> Integer
countChange n xs = fromIntegral . length $ filter ((== n) . sum) $
                        concatMap (comb xs) [1..n]
    where
    comb _ 0    = [[]]
    comb xs k   = [y:ys | l@(y:xs') <- tails xs, ys <- comb l (k-1)]

上述幼稚方法存在一个显着的性能问题,即递归调用comb 反复重新计算k-1 个组合。

我想通过使用最小不动点来添加结果记忆,即。由Data.Function.fix 。 我已经添加了一个自递归函数的声明,但是失去了如何实现memoize 函数的想法:

countChange :: Integer -> [Integer] -> Integer
countChange n xs = fromIntegral . length $ filter ((== n) . sum) $
                        concatMap (fix (memoize . comb) xs) [1..n]
    where
    comb _ _ 0    = [[]]
    comb xs f k   = [y:ys | l@(y:xs') <- tails xs, ys <- f (fix (memoize . comb) l (k-1))]
    memoize f     = undefined  -- ??

您能否就如何解决实施提出一些建议,还是我的想法完全错误?

【问题讨论】:

  • 你在玩 CodeWars 吗?
  • @Arnon 是的,但这是我的扩展挑战。已经用Data.Map写了memoization,但是很好奇如何通过定点函数来实现。
  • 因为这个 kata 的解决方案非常简单,如果您以数学方式而不是编程方式处理它。我认为数学解决方案是他们的目标。它不需要任何记忆。

标签: haskell memoization


【解决方案1】:

当尝试通过递归实现自动记忆时,您必须在递归组合器本身中执行此操作,因为每个递归调用都必须共享“内存”(即存储记忆值的位置)。

例如,对于斐波那契数列,您应该编写类似

的内容
fibo' _ 0 = 1
fibo' _ 1 = 1
fibo' f n = f (n - 1) + f (n - 2)

fibo = memoizingFix fibo'

memoizingFix 的位置取决于您要记忆的功能。最通用的方法可能是将 Data.Map 保存在 State Monad 中,但您可能希望使用不太通用的更有效的数据结构(例如可变数组)。

最后一件事,在实现您的 memoizeFix 组合器时,请记住您是要存储从一个调用到另一个调用的值还是仅在当前递归中。 (即:如果我运行fibo hugeValue,那么fibo (hugeValue + 1) 的第二次调用将与第一次或几乎立即一样长吗?)

(注意:我自愿没有给你 memoizeFix 组合器,因为它似乎你愿意理解并自己找到,但请随意询问 - 甚至谷歌它,它几乎在互联网上无处不在- 如果你需要。)

【讨论】:

    猜你喜欢
    • 2013-08-30
    • 2013-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-26
    • 1970-01-01
    • 2010-10-27
    • 1970-01-01
    相关资源
    最近更新 更多