Haskell中的两个参数memoization

时间:2011-04-05 13:43:52

标签: haskell memoization

我正在尝试记住以下功能:

gridwalk x y
    | x == 0 = 1
    | y == 0 = 1
    | otherwise = (gridwalk (x - 1) y) + (gridwalk x (y - 1))

this我想出了以下解决方案:

gw :: (Int -> Int -> Int) -> Int -> Int -> Int
gw f x y
    | x == 0 = 1
    | y == 0 = 1
    | otherwise = (f (x - 1) y) + (f x (y - 1))

gwlist :: [Int]
gwlist = map (\i -> gw fastgw (i `mod` 20) (i `div` 20)) [0..]

fastgw :: Int -> Int -> Int
fastgw x y = gwlist !! (x + y * 20)

然后我可以这样打电话:

gw fastgw 20 20

是否有更简单,更简洁和更通用的方法(注意我必须在gwlist函数中硬编码最大网格尺寸,以便从2D转换为1D空间,以便我可以访问记忆列表)在Haskell中记忆具有多个参数的函数?

4 个答案:

答案 0 :(得分:13)

您可以使用列表列表来记忆这两个参数的函数结果:

memo :: (Int -> Int -> a) -> [[a]]
memo f = map (\x -> map (f x) [0..]) [0..]


gw :: Int -> Int -> Int
gw 0 _ = 1
gw _ 0 = 1
gw x y = (fastgw (x - 1) y) + (fastgw x (y - 1))

gwstore :: [[Int]]
gwstore = memo gw

fastgw :: Int -> Int -> Int
fastgw x y = gwstore !! x !! y

答案 1 :(得分:9)

使用来自hackage的data-memocombinators软件包。它提供了易于使用的记忆技术,并提供了一种简单易用的方法:

import Data.MemoCombinators (memo2,integral)

gridwalk = memo2 integral integral gridwalk' where
  gridwalk' x y
    | x == 0 = 1
    | y == 0 = 1
    | otherwise = (gridwalk (x - 1) y) + (gridwalk x (y - 1))

答案 2 :(得分:5)

以下是使用MemoTrie包中的Data.MemoTrie来记忆该功能的版本:

import Data.MemoTrie(memo2)

gridwalk :: Int -> Int -> Int
gridwalk = memo2 gw
  where
    gw 0 _ = 1
    gw _ 0 = 1
    gw x y = gridwalk (x - 1) y + gridwalk x (y - 1)

答案 3 :(得分:3)

如果想要最大限度的通用性,可以记住一个记忆功能。

memo :: (Num a, Enum a) => (a -> b) -> [b]
memo f = map f (enumFrom 0)

gwvals = fmap memo (memo gw)

fastgw :: Int -> Int -> Int
fastgw x y = gwvals !! x !! y

此技术适用于具有任意数量参数的函数。

编辑:感谢Philip K.指出原始代码中的错误。最初memo有一个“有界”约束而不是“Num”,并开始minBound的枚举,这只对自然数有效。

列表不是用于记忆的良好数据结构,因为它们具有线性查找复杂性。使用Map或IntMap可能会更好。或look on Hackage

请注意,此特定代码确实依赖于懒惰,因此如果您想切换到使用Map,则需要从列表中获取大量元素,如:

gwByMap :: Int -> Int -> Int -> Int -> Int
gwByMap maxX maxY x y = fromMaybe (gw x y) $ M.lookup (x,y) memomap
 where
  memomap = M.fromList $ concat [[((x',y'),z) | (y',z) <- zip [0..maxY] ys]
                                              | (x',ys) <- zip [0..maxX] gwvals]

fastgw2 :: Int -> Int -> Int
fastgw2 = gwByMap 20 20

我认为ghc在这种情况下可能很愚蠢,您可能需要取消xy参数,如下所示:

gwByMap maxX maxY = \x y -> fromMaybe (gw x y) $ M.lookup (x,y) memomap