2

This is my code:

import Data.Function.Memoize
import Debug.Trace

foo :: Int -> Int -> Int
foo a = memoFix fooMemo where 
    fooMemo f x = a + (trace (show x) cont) where
        cont = if x == 0 then 0 else x + f (x - 1)

main = do
    print $ foo 0 5
    print $ foo 0 5
    print $ foo 0 5

I expected it to print:

3
2
1
0
6
6
6

But, instead, it prints this:

3
2
1
0
6
3
2
1
0
6
3
2
1
0
6

In other words, the function is not memoized as I expected it to be. This is probably because each time "foo 0" is called, a new memo-table is created for "foo". How can I force GHC to evaluate "memoFix fooMemo" only once, so that it doesn't create more than one memotable?

3
  • What package is Data.Function.Memoize from? Commented Apr 25, 2015 at 3:56
  • @DanielWagner memoize
    – Cirdec
    Commented Apr 25, 2015 at 3:58
  • 3
    FWIW, I see a very different behavior with your code than what you report. I think perhaps your actual code is using 3 as the last argument rather than 5. Commented Apr 25, 2015 at 3:58

2 Answers 2

9

The problem is that the memotable is created for each parameter value, foo 0 etc., not for the whole of foo. And then those memotables are not shared from one invocation of foo to the next. The solution is to make sure to also memoize the whole of foo:

import Data.Function.Memoize
import Debug.Trace

foo :: Int -> Int -> Int
foo = memoize foo1 where
    foo1 a = memoFix fooMemo where 
        fooMemo f x = a + (trace (show x) cont) where
            cont = if x == 0 then 0 else x + f (x - 1)

main = do
    print $ foo 0 5
    print $ foo 0 5
    print $ foo 0 5

BTW I find the following way of writing it easier than using memoFix:

foo :: Int -> Int -> Int
foo = memoize2 $ \a x ->
    let cont = if x == 0 then 0 else x + foo a (x - 1)
    in a + (trace (show x) cont)
6

Like this:

main = let f = foo 0 in do
    print $ f 5
    print $ f 5
    print $ f 5

Not the answer you're looking for? Browse other questions tagged or ask your own question.