[clean-list] Memoization of recursive functions using Clean arrays
Maks Verver
maksverver at geocities.com
Mon Aug 20 17:15:33 MEST 2012
Hi Pieter,
On Mon, 20 Aug 2012 12:54:38 +0200
Pieter Koopman <pieter at cs.ru.nl> wrote:
> By using =: in the definition of memo instead of =, you create a
> graph that is evaluated at most once.
Thanks, I had overlooked the differences between graphs/constants and
global/local definitions. Using =: does allow me to solve my problems,
but it also raises a couple more questions.
I've now rewritten my code like this:
fib_rec :: (Int -> Int) Int -> Int
fib_rec _ 0 = 0
fib_rec _ 1 = 1
fib_rec f i = (f (i - 2) + f (i - 1)) rem 1000000
memoize :: ((Int -> Int) -> Int -> Int) Int -> (Int -> Int)
memoize f max = g
where
g = select memo
memo :: {Int}
memo = { f g i \\ i <- [0..max] }
fib =: memoize fib_rec 10000
The =: in the last line is required to prevent the memo from being
recomputed unnecessarily. However, there are a couple of weird
things about this code:
1. My program segfaults when I try to call fib with an argument
outside the range of the array, even when compiling with -ci. Of
course that can't work, but I'd expect an array-index-out-of-bounds
error in that case. Could this be a bug in the code generator?
2. I'd like the type of `memoize' to be ((Int -> a) -> Int -> a) Int ->
(Int -> a). But in that case I don't know how to type memo; {a} is not
allowed, and omitting the type of memo entirely fails due to unresolved
overloading. Is there a solution for this?
3. The desired sharing of memo seems to occur only if I define g as a
partially applied function. For example, defining:
g i = memo.[i]
or:
g i = select memo i
or:
g =: \i -> memo.[i]
... results in the memo being recomputed for every invocation of g (and
thus exponential runtime). But if I use a list instead of an array
for the memo, this doesn't occur: `g i = memo!!i' works fine.
Apparently (\y -> f x y) isn't equivalent to (f x). That's really
surprising!
- Maks.
More information about the clean-list
mailing list