在Haskell中记住Double函数

时间:2013-07-16 19:02:57

标签: haskell memoization

我有一个功能

slow :: Double -> Double

经常被调用(数亿次),但只能调用大约一千个离散值。这似乎是备忘录的绝佳候选者,但我无法弄清楚如何记忆Double的功能。

制作列表的标准技术不起作用,因为它不是整数类型。我查看了Data.MemoCombinators,但它本身并不支持双打。有bits函数用于处理更多数据类型,但Double不是Data.Bits的实例。

有没有一种优雅的方式来记住`慢?

2 个答案:

答案 0 :(得分:6)

您可以随时使用ugly-memo。内部是不纯的,但它很快并且做你需要的(除非参数是NaN)。

答案 1 :(得分:3)

我认为StableMemo应该完全符合您的要求,但我对此没有任何经验。


有两种主要方法:使用Ord属性将密钥存储在树结构中,如Map。这不需要您需要的整体属性,例如:一个MemoTrie方法;它因此变慢但很简单。

另一种适用于更常见类型的替代方法是将无序地映射到具有Hash function的大型整数域,以便将密钥存储在hash map中。由于HashMap的界面与Map的界面基本匹配,因此速度会快得多,但同样简单,所以你可能想要这样做。

现在,遗憾的是完全MemoCombinators一样简单。它直接建立在IntTrie上,专门用于提供惰性/无限/纯接口。相比之下,Map和特别HashMap都可以很好地用于不纯的记忆,但本身并不能纯粹地做到这一点。你may throw in some UnsafePerformIO(呃哦),或者只是在IO monad(yuk!)中公开地做。或者使用StableMemo

但如果您已经知道它将会是哪个值,那么它实际上是简单而安全的,至少大多数调用在编译时。然后你可以在开头用这些值填充本地哈希映射,并在每次调用时查找它是否存在,否则只需直接调用昂贵的函数:

import qualified Data.HashMap.Lazy as HM

type X = Double  -- could really be anything else

notThatSlow :: Double -> X
notThatSlow = \v -> case HM.lookup v memo of
                 Just x  -> x
                 Nothing -> slow v
 where memo = HM.fromList [ (v, x) | v<-expectedValues, let x = slow v ]