It is possible to improve "raw" Fibonacci recursive procedure
Fib[n_] := If[n < 2, n, Fib[n - 1] + Fib[n - 2]]
with
Fib[n_] := Fib[n] = If[n < 2, n, Fib[n - 1] + Fib[n - 2]]
in Wolfram Mathematica.
First version will suffer from exponential explosion while second one will not since Mathematica will see repeating function calls in expression and memoize (reuse) them.
Is it possible to do the same in OCaml?
How to improve
let rec fib n = if n<2 then n else fib (n-1) + fib (n-2);;
in the same manner?
You pretty much do what the mathematica version does but manually:
Here I choose a hashtable to store already computed results instead of recomputing them. Note that you should still beware of integer overflow since we are using a normal and not a big int.
The solution provided by rgrinberg can be generalized so that we can memoize any function. I am going to use associative lists instead of hashtables. But it does not really matter, you can easily convert all my examples to use hashtables.
First, here is a function
memo
which takes another function and returns its memoized version. It is what nlucaroni suggested in one of the comments:The function
memo f
keeps a listm
of results computed so far. When asked to computef x
it first checksm
to see iff x
has been computed already. If yes, it returns the result, otherwise it actually computesf x
, stores the result inm
, and returns it.There is a problem with the above
memo
in casef
is recursive. Oncememo
callsf
to computef x
, any recursive calls made byf
will not be intercepted bymemo
. To solve this problem we need to do two things:In the definition of such a recursive
f
we need to substitute recursive calls with calls to a function "to be provided later" (this will be the memoized version off
).In
memo f
we need to providef
with the promised "function which you should call when you want to make a recursive call".This leads to the following solution:
To demonstrate how this works, let us memoize the naive Fibonacci function. We need to write it so that it accepts an extra argument, which I will call
self
. This argument is what the function should use instead of recursively calling itself:Now to get the memoized
fib
, we computeYou are welcome to try it out to see that
fib_memoized 50
returns instantly. (This is not so formemo f
wheref
is the usual naive recursive definition.)