COS 441 - Examples of coroutines in ML


datatype tree = T of tree * tree | L of int

datatype ('v,'answer) Arg = YIELD of 'v * ('v,'answer) Stream  |  DONE
withtype ('v,'answer) Stream = (('v,'answer) Arg -> 'answer) -> 'answer
     and ('v,'answer) Consumer = ('v,'answer) Arg -> 'answer

fun walk(T(a,b),f, k) = walk(a,f, fn f'=>walk(b,f',k))
  | walk(L x, f, k) = f(YIELD(x, k))

fun terminatedWalk(t) = fn f => walk(t,f, fn f' => f' DONE)

fun print'em(YIELD(i, k)) = (print(Int.toString i); print " "; k print'em)
  | print'em DONE = ()

fun samefringe(t1, t2) = 
  let fun loop(k1, k2) =
        k1(fn x1 => k2(fn x2 =>
          case (x1,x2) 
           of (YIELD(i,k1'), YIELD(j,k2')) =>
                      if i=j then loop(k1',k2') else false
            | (DONE, DONE) => true
            | _ => false))
   in loop(terminatedWalk t1, terminatedWalk t2)
  end

val t1 = T(T(T(L 1, L 2),L 3),T(L 4, L 5))

val t2 = T(L 1, T(L 2, T(T(L 3, L 4), L 5)))

val t3 = T(L 1, T(L 2, T(T(L 3, L 5), L 4)));

val t1t2 = samefringe(t1,t2);

val t1t3 = samefringe(t1,t3);

Here's an example using call-with-current-continuation (callcc):

structure C = SMLofNJ.Cont
type 'a cont = 'a C.cont
val callcc: ('a cont -> 'a) -> 'a = C.callcc
val throw : 'a cont -> ('a -> 'b) = C.throw

exception Error
exception Terminated

type 'a generator = unit->'a

fun badcont() = callcc(fn k => 
                 (callcc(fn k' => throw k k'); raise Error))

fun mkGen (walker : ('a -> unit) -> unit) : 'a generator = 
  let val yieldref : 'a cont ref = ref (badcont())
      val nextref : unit cont ref = ref (badcont())

      fun yield i = 
	    callcc(fn k =>
                   (nextref := k;  throw (!yieldref) i))

      fun next() =
            callcc(fn k => 
                  (yieldref := k;  throw (!nextref) ()))
 
      val first = callcc(fn k =>
                    (callcc(fn k' => throw k k');
                     walker yield;
                     raise Terminated))

    in  nextref := first;
       next
   end

fun genPrint(ig : int option generator) =
 let fun loop() = 
        case ig() of SOME i => (print(Int.toString i); print " "; loop())
                   | NONE => ()
  in loop()
 end

datatype tree = T of tree * tree | L of int

fun treeGen(t : tree) : int option generator =
 mkGen(fn yield : (int option -> unit) =>
    let fun walk(T(a,b)) = (walk(a); walk(b))
          | walk(L x) = yield (SOME x)
     in walk t; yield NONE
    end)

val t1 = T(T(T(L 1, L 2),L 3),T(L 4, L 5))

val t2 = T(L 1, T(L 2, T(T(L 3, L 4), L 5)))

val t3 = T(L 1, T(L 2, T(T(L 3, L 5), L 4)));

val _ = genPrint(treeGen t1);

fun samefringe(t1, t2) = 
  let val g1 = treeGen t1  and  g2 = treeGen t2
      fun loop() =
          case (g1(), g2())
           of (SOME i, SOME j) => if i=j then loop() else false
            | (NONE, NONE) => true
            | _ => false
   in loop()
  end

val t1 = T(T(T(L 1, L 2),L 3),T(L 4, L 5))

val t2 = T(L 1, T(L 2, T(T(L 3, L 4), L 5)))

val t3 = T(L 1, T(L 2, T(T(L 3, L 5), L 4)));

val t1t2 = samefringe(t1,t2);

val t1t3 = samefringe(t1,t3);

Back to COS 441 front page | Course Newsgroup | Assignments