Let us consider the following implementation of the Continuation monad, for CPS-style computations yielding and integer:
module Cont : sig
type 'a t = ('a -> int) -> int
val return : 'a -> 'a t
val bind : 'a t -> ('a -> 'b t) -> 'b t
val callCC: (('a -> 'b t) -> 'a t) -> 'a t
end = struct
type 'a t = ('a -> int) -> int
let return x =
fun cont -> cont x
let bind m f =
fun cont -> m (fun x -> (f x) cont)
let callCC k =
fun cont -> k (fun x -> (fun _ -> cont x)) cont
end
How can we rewrite the CPS-style implementation of gcd computation (see How to memoize recursive functions?) and especially the memoization to take advantage of the Cont monad?
After defining
let gcd_cont k (a,b) =
let (q, r) = (a / b, a mod b) in
if r = 0 then Cont.return b else k (b,r)
I tried to use the type solver to give me cue about the type that the memoization function should have:
# let gcd memo ((a,b):int * int) =
Cont.callCC (memo gcd_cont (a,b)) (fun x -> x)
;;
val gcd :
(((int * int -> int Cont.t) -> int * int -> int Cont.t) ->
int * int -> (int -> 'a Cont.t) -> int Cont.t) ->
int * int -> int = <fun>
However I could not turn this hint into an actual implementation. Is someone able to do this? The logic behind using “callCC” in the memoization function is that if a value is found in the cache, then this is is an early exit condition.