这是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
任何有关它的提示?
答案 0 :(得分:11)
我可以想到两种方法 -
创建泛型 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
几乎立即返回。
如果你知道你的函数的参数是Int
,并且你需要使用0..n
和0..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)
,使用结果列表作为自己的状态存储。