Two parameter memoization in Haskell

前端 未结 4 1606
盖世英雄少女心
盖世英雄少女心 2020-12-15 07:45

I\'m trying to memoize the following function:

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


        
相关标签:
4条回答
  • 2020-12-15 08:03

    Here is a version using Data.MemoTrie from the MemoTrie package to memoize the function:

    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)
    
    0 讨论(0)
  • 2020-12-15 08:08

    Use the data-memocombinators package from hackage. It provides easy to use memorization techniques and provides an easy and breve way to use them:

    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))
    
    0 讨论(0)
  • 2020-12-15 08:09

    You can use a list of lists to memoize the function result for both parameters:

    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
    
    0 讨论(0)
  • 2020-12-15 08:11

    If you want maximum generality, you can memoize a memoizing function.

    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
    

    This technique will work with functions that have any number of arguments.

    Edit: thanks to Philip K. for pointing out a bug in the original code. Originally memo had a "Bounded" constraint instead of "Num" and began the enumeration at minBound, which would only be valid for natural numbers.

    Lists aren't a good data structure for memoizing, though, because they have linear lookup complexity. You might be better off with a Map or IntMap. Or look on Hackage.

    Note that this particular code does rely on laziness, so if you wanted to switch to using a Map you would need to take a bounded amount of elements from the list, as in:

    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
    

    I think ghc may be stupid about sharing in this case, you may need to lift out the x and y parameters, like this:

    gwByMap maxX maxY = \x y -> fromMaybe (gw x y) $ M.lookup (x,y) memomap
    
    0 讨论(0)
提交回复
热议问题