我正在尝试记住以下功能:
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中记忆具有多个参数的函数?
答案 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在这种情况下可能很愚蠢,您可能需要取消x
和y
参数,如下所示:
gwByMap maxX maxY = \x y -> fromMaybe (gw x y) $ M.lookup (x,y) memomap