我想记住一个类型的函数,比如说,
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'
。
我的问题是,记住这样一个函数的好方法是什么?
答案 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')
其中memoKey
是Key
的备忘录。
请记住,Value
可能是一个更复杂的类型,具有计算免费赠品所需的信息,然后您可以丢弃最终用户的额外信息。
如果您无法将freebies
转换为representative
的形式,那么我认为您对纯备忘录策略感到不满。这是因为如果你按照你建议的方式做到这一点,免费赠品表中的值将取决于首先评估的内容,这在纯Haskell中是禁止的。 (即使您知道值将是相同的,纯粹的记忆策略甚至不能取决于评估顺序)
您也可以使用显式状态保存表格的方法,或基于unsafePerformIO
的不纯备忘录表。