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?

AJF
  • 11,767
  • 2
  • 37
  • 64
MaiaVictor
  • 51,090
  • 44
  • 144
  • 286

2 Answers2

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)
Ørjan Johansen
  • 18,119
  • 3
  • 43
  • 53
6

Like this:

main = let f = foo 0 in do
    print $ f 5
    print $ f 5
    print $ f 5
Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380