(** Continuations and Continuation Passing Style (CPS) *) (** Lecture notes originally by Michael Lee *) (* While in the middle of evaluating an expression, the *continuation* represents the rest of the expression to be evaluated. Consider the following expression: h (g (f x)) After evaluating (f x), we might represent the continuation as: h (g [[ ]]) Where the semantic brackets ([[ ]]) represent where evaluation picks back up. Normally, (f x) would return a result, which would get picked up by the continuation, and evaluation would proceed as usual. We call this the "direct style" of programming. Alternatively, we could represent the continuation as a function: fun v -> (h (g v)) And f could *call this continuation* with the result of its application to x: f x (fun v -> (h (g v)))) This makes the flow of control from f to its continuation explicit. We call this *continuation passing style* (CPS). *) (* some temperature conversion functions written in direct style *) let k2c (t: float) : float = t -. 273.15 let c2f (t: float) : float = t *. (9. /. 5.) +. 32. let f2string (t: float) : string = if t < 32. then "Brrrrrr...." else if t > 90. then "Hot!" else "Comfy" let k2string (t: float) : string = f2string (c2f (k2c t)) (* to convert these to CPS, each function needs to take the continuation as * an additional argument (`k` is traditionally used as the name of the * continuation function, but try naming it `return`!) *) (* Note the type of the continuation: * It's a function that takes the result of the direct-style function and * returns an unspecified type we'll call 'k. The result of the whole CPS * function is 'k *) let k2c_cps (t: float) (k: float -> 'k) : 'k = k (t -. 273.15) let c2f_cps (t: float) (k: float -> 'k) : 'k = k (t *. (9. /. 5.) +. 32.) let f2string (t: float) (k: string -> 'l) : 'k = k (if t < 32. then "Brrrrrr...." else if t > 90. then "Hot!" else "Comfy") let k2string t (k: string -> 'k) : 'k = k2c_cps t (fun t1 -> (* see how CPS explicitly encodes control flow! *) c2f_cps t1 (fun t2 -> f2string t2 (fun t3 -> (* if you squint at this, it kinda looks imperative *) k t3))) (* especially if you rename k "return" *) (* Call with the identity function to just return the final answer *) let _ = k2string 60. (fun x -> x)