Haskell中的2或3个参数的记忆/动态编程

时间:2014-01-28 11:17:25

标签: haskell dynamic-programming memoization

这是Haskell中一个简单的memoization,函数f1采用一个参数(是的,Fibonacci):

f1 = [calc n | n <- [0..]]
     where calc 0 = 0
           calc 1 = 1
           calc n = f1 !! (n-1) + f1 !! (n-2)

现在,对于带有2个参数的函数f2或带3个参数的f3,如何做?

对于f2,列表列表是最好的方法吗?或者可以使用不同的数据结构?

f2 = [[calc n m | n <- [0..]] | m <- [0..]]
     where calc 0 0 = 0
           calc a b = // ...something using (f2 !! a !! b)

对于f3 a b c而言,鉴于max_a * max_b * max_c是可管理的,此备忘录/动态编​​程将如何运作?

我正在寻找最简单/最直接的方法,如果可能的话,使用标准的Haskell库。

修改

正如克里斯·泰勒的回答所建议的那样,我尝试使用MemoCombinators.hs v0.5.1,但它失败了,就像这样:

Could not find module `Data.IntTrie'
Use -v to see a list of the files searched for.

Illegal symbol '.' in type
Perhaps you intended -XRankNTypes or similar flag
to enable explicit-forall syntax: forall <tvs>. <type>

我需要在“普通”haskell中运行此版本:GHCi, version 7.6.3

任何有关它的提示?

2 个答案:

答案 0 :(得分:11)

我可以想到两种方法 -

1。 MemoCombinators

创建泛型 memoized函数的最简单方法可能是使用data-memocombinators库。假设您有以下两个参数函数。

f :: Int -> Int -> Integer
f 0 _ = 1
f _ 0 = 1
f a b = f (a-1) b + f a (b-1)

您可以尝试拨打f 20 20,但要做好准备等待一段时间。您可以使用

轻松编写备忘录版本
import Data.MemoCombinators

f :: Int -> Int -> Integer
f = memo2 integral integral f'
  where
    f' 0 _ = 1
    f' _ 0 = 1
    f' a b = f (a-1) b + f a (b-1)

请注意,在辅助函数f'中,递归调用f',而不是memoized函数f。现在调用f 20 20几乎立即返回。

2。列表......

如果你知道你的函数的参数是Int,并且你需要使用0..n0..m来计算f (n+1) (m+1),那么它可能有意义使用列表列表方法。但是,请注意,这与函数的参数数量有很大关系(特别是,如果您有两个以上的参数,很难一目了然地说明函数在做什么)。

flist :: [[Integer]]
flist = [[f' n m | m <- [0..]] | n <- [0..]]
 where
  f' _ 0 = 1
  f' 0 _ = 1
  f' a b = flist !! (a-1) !! b + flist !! a !! (b-1)

f :: Int -> Int -> Integer
f a b = flist !! a !! b

答案 1 :(得分:2)

由于Haskell很懒惰,你可以通过自己调用函数来记忆函数。

例如,Haskell中的一个斐波纳契生成器是这样的:

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

(来自http://www.haskell.org/haskellwiki/The_Fibonacci_sequence

,使用结果列表作为自己的状态存储。