[clean-list] Memoization of recursive functions using Clean arrays
Pieter Koopman
pieter at cs.ru.nl
Mon Aug 20 12:54:38 MEST 2012
Hi Maks,
You can use a lazy array and make it graph to avoid recomputation:
memo :: {Int}
memo =:
{createArray (MaxFib+1) 0
& [1] = 1
, [i] = (memo.[i-1] + memo.[i-2]) rem 10^6 \\ i <- [2..MaxFib]
}
or
memo :: {Int}
memo =: {createArray (MaxFib+1) 0 & [i] = f i \\ i <- [0..MaxFib]}
where
f 0 = 0
f 1 = 1
f i = (memo.[i-1] + memo.[i-2]) rem 10^6
By using =: in the definition of memo instead of =, you create a graph
that is evaluated at most once. Since it is a lazy array the array
elements are only calculated when they are needed. By changing the type
of memo to {#Int} you create a unboxed array which is strict but stored
more efficiently.
The definition of fib remains
fib j = memo.[j]
Does this solve you problem?
Best, Pieter
On 19/08/2012 6:37 PM, Maks Verver wrote:
> Hi Pieter,
>
> On Fri, 17 Aug 2012 17:32:12 +0200
> Pieter Koopman <pieter at cs.ru.nl> wrote:
>> The problem is that you need inline updates of your array to obtain
>> the desired memoization effect. The way to obtain inline updates is
>> to create an array and to pass it as a unique object in your function
>> f.
> Thanks for the suggestion! I suppose that works, but that's a strict
> computation. A really nice property of the Haskell version of the code
> is that it's still a lazy computation; array values are computed only
> if/when they are needed.
>
> Making the array elements boxed/non-strict in your version of the code
> doesn't achieve the same effect because computing the final array value
> still requires expanding all function calls (parts of which may be left
> uncomputed, but that just means you use a lot of memory in addition to
> a lot of time -- the worst of both worlds).
>
> Maybe the way I originally phrased my question was misleading way,
> because some further experimentation reveals that my problem doesn't
> apply to arrays specifically, but values in Clean not being shared
> when I expect them to.
>
> For example, this implementation:
>
> fib i = memo!!i
>
> memo = map f [0..]
>
> f 0 = 0
> f 1 = 1
> f i = fib (i - 2) + fib (i - 1) rem 1000000
>
> ... seems to have comparable (exponential-time) performance. I'd
> expect the value of `memo' to be shared so that its elements aren't
> recomputed but apparently that doesn't happen. Why not? Is there a
> way to make Clean behave more like Haskell in this regard?
>
> - Maks.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.science.ru.nl/pipermail/clean-list/attachments/20120820/b65bf11c/attachment.html>
More information about the clean-list
mailing list