记住便宜的副作用

时间:2012-02-26 05:41:59

标签: haskell memoization

我想记住一个类型的函数,比如说,

f :: Int -> Integer

我可以轻松地使用例如MemoCombinators包,因此:

f_ = Memo.integral f

然而,当给出一对(x, f x)时,有很多其他点可以轻松计算f f x

freebies :: (Int, Integer) -> [(Int, Integer)]

但是给定一个点x',为x计算一些elem x' . map fst $ freebies (x, f x)并不便宜。因此,我希望将这些额外的(x', y')对存储起来,以便以后可以有效地计算f x'

我的问题是,记住这样一个函数的好方法是什么?

1 个答案:

答案 0 :(得分:2)

要使用 pure memoization执行此操作,您需要找到一种方法将免费赠品的x映射回生成它的点。如果您想要考虑纯memoization的功能,不要将其视为更新的缓存表;相反,将其视为逐渐简化的数据依赖图。你需要一种让免费赠品指向计算它们的方法。

假设你有:

-- Representative k finds a k', where it is easy to calculate
-- k from (k')'s value (this calculation is the Value -> Value
-- function)
-- There should be multiple (k')'s per k; and representative k' 
-- on one of those should return (k', const v), where v is the
-- value.
representative :: Key -> (Key, Value -> Value)

然后你可以记住:

table = memoKey go
    where
    go k = let (k', vf) = representative k in
           vf (table k')

其中memoKeyKey的备忘录。

请记住,Value可能是一个更复杂的类型,具有计算免费赠品所需的信息,然后您可以丢弃最终用户的额外信息。

如果您无法将freebies转换为representative的形式,那么我认为您对备忘录策略感到不满。这是因为如果你按照你建议的方式做到这一点,免费赠品表中的值将取决于首先评估的内容,这在纯Haskell中是禁止的。 (即使您知道值将是相同的,纯粹的记忆策略甚至不能取决于评估顺序)

您也可以使用显式状态保存表格的方法,或基于unsafePerformIO的不纯备忘录表。