first commit
This commit is contained in:
commit
f8f05a731b
15 changed files with 423 additions and 0 deletions
3
doc/dune
Normal file
3
doc/dune
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
(documentation
|
||||
(package memo)
|
||||
(mld_files usage index))
|
||||
7
doc/index.mld
Normal file
7
doc/index.mld
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{0 memo}
|
||||
|
||||
[memo] is an {{:https://en.wikipedia.org/wiki/OCaml}OCaml} library for {{:https://en.wikipedia.org/wiki/Memoization}memoïzation}.
|
||||
|
||||
It provides easy ways to memoïze a function, in a type-safe and modular way and the ability to get forgetful memoïzation.
|
||||
|
||||
See {{:usage.html} usage} for a short explanation on how to use the library and {{:Memo/index.html} Memo} for a more detailled explanation.
|
||||
117
doc/usage.mld
Normal file
117
doc/usage.mld
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
{0 Usage}
|
||||
|
||||
If you had a function [fibo] defined like this:
|
||||
|
||||
{[
|
||||
let rec fibo x =
|
||||
if x < 0 then invalid_arg "fibo";
|
||||
if x < 2 then x
|
||||
else fibo (x - 1) + fibo (x - 2)
|
||||
]}
|
||||
|
||||
There's many different ways to memoïze it.
|
||||
|
||||
{1:simple_memo Simple memoïzation}
|
||||
|
||||
The easiest one is to rewrite it like this:
|
||||
|
||||
{[
|
||||
let fibo = Memo.memo (fun fibo x ->
|
||||
if x < 0 then invalid_arg "fibo";
|
||||
if x < 2 then x
|
||||
else fibo (x - 1) + fibo (x - 2))
|
||||
]}
|
||||
|
||||
It'll use the {!module:Hashtbl} module from {!module:Stdlib} directly.
|
||||
|
||||
I'd like to thank {{:https://www.lri.fr/~conchon/}Sylvain Conchon} who taught me memoïzation and how to write this [memo] function when I was his student.
|
||||
|
||||
{1:custom_memo Using your own type, [equal] and [hash] functions}
|
||||
|
||||
We provide a {!module:Memo.Make} functor. It can be useful in case you don't want to use polymorphic equality or you are doing things like {{:https://en.wikipedia.org/wiki/Hash_consing}hash consing} and you know how to compare or hash your type more efficiently.
|
||||
|
||||
{[
|
||||
let module Mem = Memo.Make(struct
|
||||
type t = int
|
||||
let equal = (=)
|
||||
let hash = Hashtbl.hash
|
||||
end)
|
||||
|
||||
let fibo = Mem.memo (fun fibo x ->
|
||||
if x < 0 then invalid_arg "fibo";
|
||||
if x < 2 then x
|
||||
else fibo (x - 1) + fibo (x - 2))
|
||||
]}
|
||||
|
||||
{1:forgetful_memo Forgetful memoïzation}
|
||||
|
||||
We provide a {!module:Memo.MakeWeak} functor. It works like the previous one, but the bindings in the memoïzation cache will be weak, allowing the garbage collector to remove them if they are not used somewhere else.
|
||||
|
||||
{[
|
||||
let module Mem = Memo.MakeWeak(struct
|
||||
type t = int
|
||||
let equal = (=)
|
||||
let hash = Hashtbl.hash
|
||||
end)
|
||||
|
||||
let fibo = Mem.memo (fun fibo x ->
|
||||
if x < 0 then invalid_arg "fibo";
|
||||
if x < 2 then x
|
||||
else fibo (x - 1) + fibo (x - 2))
|
||||
]}
|
||||
|
||||
I'd like to thank {{:https://www.lri.fr/~filliatr/}Jean-Christophe Filliâtre} who taugh me forgetful memoïzation when I was doing research on {{:https://en.wikipedia.org/wiki/Binary_decision_diagram}binary decision diagram} under his direction while I was a first year master student.
|
||||
|
||||
{1:fake_memo Fake memoïzation}
|
||||
|
||||
We provide a {!module:Memo.Fake} functor. It is useful if you want to quickly test a function you memoïzed with our {!module:Memo.Make} or {!module:Memo.MakeWeak} functor, but without memoïzing it. It'll basically do nothing and should be equivalent to your initial non-memoïzed function.
|
||||
|
||||
{[
|
||||
let module Mem = Memo.Fake(struct
|
||||
type t = int
|
||||
let equal = (=)
|
||||
let hash = Hashtbl.hash
|
||||
end)
|
||||
|
||||
let fibo = Mem.memo (fun fibo x ->
|
||||
if x < 0 then invalid_arg "fibo";
|
||||
if x < 2 then x
|
||||
else fibo (x - 1) + fibo (x - 2))
|
||||
]}
|
||||
|
||||
{1:custom_cache Using your own defined cache}
|
||||
|
||||
With the {!module:Memo.Mk} functor, you can also directly provide a [Cache] module, which should have the signature {!module-type:Hashtbl.S}. We will include your cache module and use it to define a [memo] function:
|
||||
|
||||
{[
|
||||
let module Mem = Memo.Mk(
|
||||
Hashtbl.Make(struct
|
||||
type t = int
|
||||
let equal = (=)
|
||||
let hash = Hashtbl.hash
|
||||
end)
|
||||
end)
|
||||
|
||||
let fibo = Mem.memo (fun fibo x ->
|
||||
if x < 0 then invalid_arg "fibo";
|
||||
if x < 2 then x
|
||||
else fibo (x - 1) + fibo (x - 2))
|
||||
]}
|
||||
|
||||
This example is useless and equivalent to using the {!module:Memo.Make} functor directly.
|
||||
|
||||
If you find a real use case for this which doesn't need new dependencies, contact me and I'll be happy to add a new functor to the library.
|
||||
|
||||
It should be useful only if you want to use another {!module:Hashtbl} implementation or things like this.
|
||||
|
||||
{1:tuning Tuning}
|
||||
|
||||
There's a default value for the initial cache size. You can set it to the value of your choice, reset it to the default and get the current value like this:
|
||||
|
||||
{[
|
||||
Memo.set_initial_cache_size 1024;
|
||||
Memo.reset_initial_cache_size ();
|
||||
let curr_size = Memo.get_initial_cache_size ()
|
||||
]}
|
||||
|
||||
Note that with the current implementation of hash tables in OCaml, it's better if you choose a power of two. You may saw some code using a prime number, it's because some years ago it was the best thing to do as the hash tables implementation was different. {{:https://www.lri.fr/~filliatr/}Jean-Christophe Filliâtre} explained this to me, thanks again ! Also keep in mind that if you use your own defined cache thanks to the {!module:Memo.Mk} functor, it may not be the right thing to do.
|
||||
Loading…
Add table
Add a link
Reference in a new issue