4 people like it.
Like the snippet!
Continuation Monad with Call/CC
This is an implementation of the Continuation monad using a type, taking an exception handler, and allowing for Call/CC. This specific implementation is mostly Matt Podwysocki's. I have a similar implementation using a purely functional, exception-handler-less version in FSharp.Monad. Until now, I haven't been able to resolve the callCC operator.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
|
type Cont<'a,'r> =
abstract Call : ('a -> 'r) * (exn -> 'r) -> 'r
let private protect f x cont econt =
let res = try Choice1Of2 (f x) with err -> Choice2Of2 err
match res with
| Choice1Of2 v -> cont v
| Choice2Of2 v -> econt v
let runCont (c:Cont<_,_>) cont econt = c.Call(cont, econt)
let throw exn = { new Cont<_,_> with member x.Call (cont,econt) = econt exn }
let callCC f =
{ new Cont<_,_> with
member x.Call(cont, econt) =
runCont (f (fun a -> { new Cont<_,_> with member x.Call(_,_) = cont a })) cont econt }
type ContinuationBuilder() =
member this.Return(a) =
{ new Cont<_,_> with member x.Call(cont, econt) = cont a }
member this.ReturnFrom(comp:Cont<_,_>) = comp
member this.Bind(comp1, f) =
{ new Cont<_,_> with
member x.Call (cont, econt) =
runCont comp1 (fun a -> protect f a (fun comp2 -> runCont comp2 cont econt) econt) econt }
member this.Catch(comp:Cont<_,_>) =
{ new Cont<Choice<_, exn>,_> with
member x.Call (cont, econt) =
runCont comp (fun v -> cont (Choice1Of2 v)) (fun err -> cont (Choice2Of2 err)) }
member this.Zero() =
this.Return ()
member this.TryWith(tryBlock, catchBlock) =
this.Bind(this.Catch tryBlock, (function Choice1Of2 v -> this.Return v
| Choice2Of2 exn -> catchBlock exn))
member this.TryFinally(tryBlock, finallyBlock) =
this.Bind(this.Catch tryBlock, (function Choice1Of2 v -> finallyBlock(); this.Return v
| Choice2Of2 exn -> finallyBlock(); throw exn))
member this.Using(res:#IDisposable, body) =
this.TryFinally(body res, (fun () -> match res with null -> () | disp -> disp.Dispose()))
member this.Combine(comp1, comp2) = this.Bind(comp1, (fun () -> comp2))
member this.Delay(f) = this.Bind(this.Return (), f)
member this.While(pred, body) =
if pred() then this.Bind(body, (fun () -> this.While(pred,body))) else this.Return ()
member this.For(items:seq<_>, body) =
this.Using(items.GetEnumerator(), (fun enum -> this.While((fun () -> enum.MoveNext()), this.Delay(fun () -> body enum.Current))))
let cont = ContinuationBuilder()
|
type Cont<'a,'r> =
interface
abstract member Call : ('a -> 'r) * (exn -> 'r) -> 'r
end
Full name: Script.Cont<_,_>
abstract member Cont.Call : ('a -> 'r) * (exn -> 'r) -> 'r
Full name: Script.Cont`2.Call
type exn = Exception
Full name: Microsoft.FSharp.Core.exn
val private protect : f:('a -> 'b) -> x:'a -> cont:('b -> 'c) -> econt:(exn -> 'c) -> 'c
Full name: Script.protect
val f : ('a -> 'b)
val x : 'a
val cont : ('b -> 'c)
val econt : (exn -> 'c)
val res : Choice<'b,exn>
union case Choice.Choice1Of2: 'T1 -> Choice<'T1,'T2>
val err : exn
union case Choice.Choice2Of2: 'T2 -> Choice<'T1,'T2>
val v : 'b
val v : exn
val runCont : c:Cont<'a,'b> -> cont:('a -> 'b) -> econt:(exn -> 'b) -> 'b
Full name: Script.runCont
val c : Cont<'a,'b>
val cont : ('a -> 'b)
val econt : (exn -> 'b)
abstract member Cont.Call : ('a -> 'r) * (exn -> 'r) -> 'r
val throw : exn:exn -> Cont<'a,'b>
Full name: Script.throw
Multiple items
val exn : exn
--------------------
type exn = Exception
Full name: Microsoft.FSharp.Core.exn
val x : Cont<'a,'b>
val callCC : f:(('a -> Cont<'b,'c>) -> #Cont<'a,'c>) -> Cont<'a,'c>
Full name: Script.callCC
val f : (('a -> Cont<'b,'c>) -> #Cont<'a,'c>)
val x : Cont<'a,'c>
val cont : ('a -> 'c)
val a : 'a
val x : Cont<'b,'c>
Multiple items
type ContinuationBuilder =
new : unit -> ContinuationBuilder
member Bind : comp1:Cont<'a1,'a2> * f:('a1 -> #Cont<'a4,'a2>) -> Cont<'a4,'a2>
member Catch : comp:Cont<'s,'t> -> Cont<Choice<'s,exn>,'t>
member Combine : comp1:Cont<unit,'h> * comp2:Cont<'i,'h> -> Cont<'i,'h>
member Delay : f:(unit -> #Cont<'f,'g>) -> Cont<'f,'g>
member For : items:seq<'a> * body:('a -> #Cont<unit,'c>) -> Cont<unit,'c>
member Return : a:'a7 -> Cont<'a7,'a8>
member ReturnFrom : comp:Cont<'a5,'a6> -> Cont<'a5,'a6>
member TryFinally : tryBlock:Cont<'n,'o> * finallyBlock:(unit -> unit) -> Cont<'n,'o>
member TryWith : tryBlock:Cont<'p,'q> * catchBlock:(exn -> Cont<'p,'q>) -> Cont<'p,'q>
...
Full name: Script.ContinuationBuilder
--------------------
new : unit -> ContinuationBuilder
val this : ContinuationBuilder
member ContinuationBuilder.Return : a:'a7 -> Cont<'a7,'a8>
Full name: Script.ContinuationBuilder.Return
val a : 'a7
val x : Cont<'a7,'a8>
val cont : ('a7 -> 'a8)
val econt : (exn -> 'a8)
member ContinuationBuilder.ReturnFrom : comp:Cont<'a5,'a6> -> Cont<'a5,'a6>
Full name: Script.ContinuationBuilder.ReturnFrom
val comp : Cont<'a5,'a6>
member ContinuationBuilder.Bind : comp1:Cont<'a1,'a2> * f:('a1 -> #Cont<'a4,'a2>) -> Cont<'a4,'a2>
Full name: Script.ContinuationBuilder.Bind
val comp1 : Cont<'a1,'a2>
val f : ('a1 -> #Cont<'a4,'a2>)
val x : Cont<'a4,'a2>
val cont : ('a4 -> 'a2)
val econt : (exn -> 'a2)
val a : 'a1
val comp2 : #Cont<'a4,'a2>
member ContinuationBuilder.Catch : comp:Cont<'s,'t> -> Cont<Choice<'s,exn>,'t>
Full name: Script.ContinuationBuilder.Catch
val comp : Cont<'s,'t>
Multiple items
type Choice<'T1,'T2> =
| Choice1Of2 of 'T1
| Choice2Of2 of 'T2
Full name: Microsoft.FSharp.Core.Choice<_,_>
--------------------
type Choice<'T1,'T2,'T3> =
| Choice1Of3 of 'T1
| Choice2Of3 of 'T2
| Choice3Of3 of 'T3
Full name: Microsoft.FSharp.Core.Choice<_,_,_>
--------------------
type Choice<'T1,'T2,'T3,'T4> =
| Choice1Of4 of 'T1
| Choice2Of4 of 'T2
| Choice3Of4 of 'T3
| Choice4Of4 of 'T4
Full name: Microsoft.FSharp.Core.Choice<_,_,_,_>
--------------------
type Choice<'T1,'T2,'T3,'T4,'T5> =
| Choice1Of5 of 'T1
| Choice2Of5 of 'T2
| Choice3Of5 of 'T3
| Choice4Of5 of 'T4
| Choice5Of5 of 'T5
Full name: Microsoft.FSharp.Core.Choice<_,_,_,_,_>
--------------------
type Choice<'T1,'T2,'T3,'T4,'T5,'T6> =
| Choice1Of6 of 'T1
| Choice2Of6 of 'T2
| Choice3Of6 of 'T3
| Choice4Of6 of 'T4
| Choice5Of6 of 'T5
| Choice6Of6 of 'T6
Full name: Microsoft.FSharp.Core.Choice<_,_,_,_,_,_>
--------------------
type Choice<'T1,'T2,'T3,'T4,'T5,'T6,'T7> =
| Choice1Of7 of 'T1
| Choice2Of7 of 'T2
| Choice3Of7 of 'T3
| Choice4Of7 of 'T4
| Choice5Of7 of 'T5
| Choice6Of7 of 'T6
| Choice7Of7 of 'T7
Full name: Microsoft.FSharp.Core.Choice<_,_,_,_,_,_,_>
val x : Cont<Choice<'s,exn>,'t>
val cont : (Choice<'s,exn> -> 't)
val econt : (exn -> 't)
val v : 's
member ContinuationBuilder.Zero : unit -> Cont<unit,'r>
Full name: Script.ContinuationBuilder.Zero
member ContinuationBuilder.Return : a:'a7 -> Cont<'a7,'a8>
member ContinuationBuilder.TryWith : tryBlock:Cont<'p,'q> * catchBlock:(exn -> Cont<'p,'q>) -> Cont<'p,'q>
Full name: Script.ContinuationBuilder.TryWith
val tryBlock : Cont<'p,'q>
val catchBlock : (exn -> Cont<'p,'q>)
member ContinuationBuilder.Bind : comp1:Cont<'a1,'a2> * f:('a1 -> #Cont<'a4,'a2>) -> Cont<'a4,'a2>
member ContinuationBuilder.Catch : comp:Cont<'s,'t> -> Cont<Choice<'s,exn>,'t>
val v : 'p
member ContinuationBuilder.TryFinally : tryBlock:Cont<'n,'o> * finallyBlock:(unit -> unit) -> Cont<'n,'o>
Full name: Script.ContinuationBuilder.TryFinally
val tryBlock : Cont<'n,'o>
val finallyBlock : (unit -> unit)
val v : 'n
member ContinuationBuilder.Using : res:'j * body:('j -> #Cont<'l,'m>) -> Cont<'l,'m> (requires 'j :> IDisposable and 'j : null)
Full name: Script.ContinuationBuilder.Using
val res : 'j (requires 'j :> IDisposable and 'j : null)
type IDisposable =
member Dispose : unit -> unit
Full name: System.IDisposable
val body : ('j -> #Cont<'l,'m>) (requires 'j :> IDisposable and 'j : null)
member ContinuationBuilder.TryFinally : tryBlock:Cont<'n,'o> * finallyBlock:(unit -> unit) -> Cont<'n,'o>
val disp : 'j (requires 'j :> IDisposable and 'j : null)
IDisposable.Dispose() : unit
member ContinuationBuilder.Combine : comp1:Cont<unit,'h> * comp2:Cont<'i,'h> -> Cont<'i,'h>
Full name: Script.ContinuationBuilder.Combine
val comp1 : Cont<unit,'h>
val comp2 : Cont<'i,'h>
member ContinuationBuilder.Delay : f:(unit -> #Cont<'f,'g>) -> Cont<'f,'g>
Full name: Script.ContinuationBuilder.Delay
val f : (unit -> #Cont<'f,'g>)
member ContinuationBuilder.While : pred:(unit -> bool) * body:Cont<unit,'d> -> Cont<unit,'d>
Full name: Script.ContinuationBuilder.While
val pred : (unit -> bool)
val body : Cont<unit,'d>
member ContinuationBuilder.While : pred:(unit -> bool) * body:Cont<unit,'d> -> Cont<unit,'d>
member ContinuationBuilder.For : items:seq<'a> * body:('a -> #Cont<unit,'c>) -> Cont<unit,'c>
Full name: Script.ContinuationBuilder.For
val items : seq<'a>
Multiple items
val seq : sequence:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Core.Operators.seq
--------------------
type seq<'T> = Collections.Generic.IEnumerable<'T>
Full name: Microsoft.FSharp.Collections.seq<_>
val body : ('a -> #Cont<unit,'c>)
member ContinuationBuilder.Using : res:'j * body:('j -> #Cont<'l,'m>) -> Cont<'l,'m> (requires 'j :> IDisposable and 'j : null)
Collections.Generic.IEnumerable.GetEnumerator() : Collections.Generic.IEnumerator<'a>
val enum : Collections.Generic.IEnumerator<'a>
Collections.IEnumerator.MoveNext() : bool
member ContinuationBuilder.Delay : f:(unit -> #Cont<'f,'g>) -> Cont<'f,'g>
property Collections.Generic.IEnumerator.Current: 'a
val cont : ContinuationBuilder
Full name: Script.cont
More information