使memoization成为Haskell的默认行为的选项

时间:2012-10-24 23:24:35

标签: haskell ghc memoization

我已经在Haskell中看到了所有其他的memoization技巧和技术,但我正在寻找的是在编译器/解释器级别中直接实现,为我处理memoization。

例如,请考虑Fibonacci函数的以下代码:

fib 0 = 1
fib 1 = 1
fib n = fib (n-1) + fib (n-2)

我想要ghc(或任何其他Haskell编译器)的某种编译器选项,默认情况下使用memoization执行上面的代码。例如,为了计算“fib 10”,首先需要计算“fib 8”和“fib 9”。此外,计算“fib 9”取决于首先计算“fib 8”。因此,在计算“fib 10”时,我希望编译器/解释器能够理解并只计算一次“fib 8”。

请注意,我不想编写一个新的Fibonacci函数来处理memoization(就像Haskell中所有其他memoization问题的情况一样)。我想要的是保持上面的功能,仍然有记忆。我不知道是否有任何Haskell编译器具有该功能,这是我的问题的一部分。你知道一个可以给我这个的Haskell编译器吗?

由于

1 个答案:

答案 0 :(得分:13)

编译器通常不会提供“memoize”选项,因为很难知道程序员想要执行memoization的位置和方式。记忆本质上是交易时间和时间。空间要求。

现在,如果您愿意以稍微不同的方式编写函数,那么 是一种解耦函数定义和使用的memoization技术的方法。

import Data.RunMemo (Memoizable, runMemo, noMemo)
import Data.MemoCombinators as Memo (integral)

fibMemoizable :: Memoizable (Integer -> Integer)
fibMemoizable recurse = go where
  go 0 = 1
  go 1 = 1
  go n = recurse (n - 1) + recurse (n - 2)

fastFib :: Integer -> Integer
fastFib = runMemo Memo.integral fibMemoizable

slowFib :: Integer -> Integer
slowFib = runMemo noMemo fibMemoizable

这使用了Luke Palmer的data-memocombinators包,以及我自己的玩具包runmemo。请注意,的内容与的内容相同,只是它为递归调用调用recurse。虽然这个可以被编入一个编译器,但我没有理由这样做,因为Haskell足够表达,无需编译器知道我们正在做什么。