Advertisement
Guest User

Untitled

a guest
Jul 20th, 2017
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
OCaml 4.47 KB | None | 0 0
  1. (* Yann Regis-Gianas implementation of co-routines using call/cc in O'Caml. *)
  2.  
  3. (* We are using Xavier Leroy's experimental Callcc library for O'Caml. *)
  4. open Callcc;;
  5. let unsome = function Some x -> x | None -> assert false
  6.  
  7. module type S = sig
  8.   (* Coroutines with input 'i and output 'o *)
  9.   type ('i,'o) coroutine
  10.   type ('i,'o) coroutine_body = ('i, 'o) coroutine -> 'i -> 'o
  11.   (* create coroutine from body function *)
  12.   val create : ('i, 'o) coroutine_body -> ('i,'o) coroutine
  13.   (* Asymmetric coroutine operator: *)
  14.   (* resume a suspended coroutine. *)
  15.   val resume: ('i,'o) coroutine -> 'i -> 'o
  16.   (* Complement to resume: suspend the current coroutine, return to caller *)
  17.   val yield : ('i, 'o) coroutine -> 'o -> 'i
  18. end
  19.  
  20. module Coroutine : S = struct
  21.  
  22.   (* A co-routine has to remember its own continuation
  23.      when it is suspended as well as the continuation of
  24.      its caller when it is resumed. *)
  25.   type ('i, 'o) coroutine_data = {
  26.     suspension : ('i cont) option ref;
  27.     caller     : ('o cont) option ref;
  28.     body       : 'i -> 'o
  29.   }
  30.  
  31.   type ('i, 'o) coroutine =
  32.       Coroutine of ('i, 'o) coroutine_data
  33.  
  34.   (* A co-routine is defined using a function that
  35.      will ultimately produce a value of type ['o]
  36.      from a value of type ['i]. This function can
  37.      interrupt itself using [yield]. *)
  38.   type ('i,'o) coroutine_body =
  39.       ('i, 'o) coroutine -> 'i -> 'o
  40.  
  41.   let resume (Coroutine co) v =
  42.     match !(co.suspension) with
  43.       (* This is the first this co-routine is runned, so we
  44.      directly use the initial function that was given
  45.      at the creation of the co-routine. *)
  46.       | None ->
  47.     callcc (fun k -> co.caller := Some k; co.body v)
  48.  
  49.       (* The co-routine has already been suspended. It
  50.      first captures the caller's continuation and
  51.      reinstall its own suspended continuation. *)
  52.       | Some suspension ->
  53.     callcc (fun k -> co.caller := Some k; throw suspension v)
  54.  
  55.   let yield (Coroutine co) v =
  56.     (* This time, this is the other around: we have to save the
  57.        co-routine continuation and restore the caller's. *)
  58.     callcc (fun k -> co.suspension := Some k; throw (unsome !(co.caller)) v)
  59.      
  60.   let create body =
  61.     let rec c = Coroutine ({
  62.       suspension = ref None;
  63.       caller     = ref None;
  64.       body       = (fun x -> body c x)
  65.     })
  66.     in
  67.     c
  68.  
  69. end
  70.  
  71. open Coroutine;;
  72.  
  73. (* A first test:
  74.    Two co-routines play ping-pong.
  75.    Pong is the master. *)
  76. let ping : (int, int) coroutine =
  77.   let rec body = fun co x ->
  78.     begin
  79.       Printf.printf "ping %d !\n%!" x;
  80.       body co (yield co (x + 1))
  81.     end
  82.   in
  83.   create body
  84.  
  85. let max_ping_pong = 11
  86.  
  87. let pong : (int, int) coroutine =
  88.   let rec body = fun co x ->
  89.     if x < max_ping_pong then begin
  90.       Printf.printf "pong %d !\n%!" x;
  91.       body co (resume ping (x + 1));
  92.     end else x
  93.   in
  94.   create body
  95.    
  96. let _ = resume pong 0
  97.  
  98. (* A second test:
  99.    Now ping and pong play pingpong but symmetrically.
  100.    This requires a mutually recursive definition of these co-routines,
  101.    which is realized through a two-steps initialization through a
  102.    reference.
  103. *)
  104.  
  105. let ping pong : (int, int) coroutine =
  106.   let rec body = fun co x ->
  107.     if x < max_ping_pong then begin
  108.       Printf.printf "ping %d !\n%!" x;
  109.       body co (resume (unsome !pong) (x + 1))
  110.     end else x
  111.   in
  112.   create body
  113.  
  114. let max_ping_pong = 11
  115.  
  116. let pong ping : (int, int) coroutine =
  117.   let rec body = fun co x ->
  118.     if x < max_ping_pong then begin
  119.       Printf.printf "pong %d !\n%!" x;
  120.       body co (resume (unsome !ping) (x + 1));
  121.     end else x
  122.   in
  123.   create body
  124.  
  125. let pingpong =
  126.   let rping = ref None in
  127.   let rpong = ref None in
  128.   let ping  = ping rpong in
  129.   let pong  = pong rping in
  130.   rping := Some ping;
  131.   rpong := Some pong;
  132.   resume ping 0
  133.  
  134. (* A third test:
  135.    An iteration through an infinite tree.
  136. *)
  137.  
  138. type 'a tree = Empty | Node of 'a tree * 'a * 'a tree
  139.  
  140. let fold_tree =
  141.   fun f tree init ->
  142.     let rec body =
  143.       fun tree accu co () ->
  144.     match tree with
  145.       | Empty -> accu
  146.       | Node (l, x, r) ->
  147.         let accu = f accu x in
  148.         yield co accu;
  149.         let accu = body l accu co () in
  150.         body r accu co ()
  151.     in
  152.     create (body tree init)
  153.  
  154. let rec infinite_tree = Node (infinite_tree, 42, infinite_tree)
  155.  
  156. let _ =
  157.   let sum accu x = x + accu in
  158.   let co_fold_tree = fold_tree sum infinite_tree 0 in
  159.   for i = 0 to 100 do
  160.     Printf.printf "Sum: %d\n" (resume co_fold_tree ())
  161.   done
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement