(* A bounded prime number filter *)

local fun p1(ic,oc,x) =
   ic inp x' =>
   if (x' mod x) = 0 then p1(ic,oc,x)
   else oc out x' => p1(ic,oc,x)

in fun p(ic,oc) =
   ic inp x =>
   (print(x:int); print "\n"; p1(ic,oc,x))
end;

exception duplicate:unit;

fun duplicate(p,n,ic,oc):beh =
   if n = 0 then raise duplicate
   else if n = 1 then p(ic,oc)
   else let port c in (p(ic,c) & duplicate(p,n-1,c,oc)) end;

fun firstNprimes(n,ic,oc) = duplicate(p,n,ic,oc);

fun from(n,oc) = oc out n => from(n+1,oc);

val firstnprimes =
   let port c and c' in (from(2,c) & firstNprimes(10,c,c')) end;


(* An infinite prime number filter *)

local fun p1(ic,oc,x) =
   ic inp x' =>
   if (x' mod x) = 0 then p1(ic,oc,x)
   else oc out x' => p1(ic,oc,x)

in fun p(ic,oc) =
   ic inp x =>
   (print(x:int); print "\n"; let port c in (p1(ic,c,x) & p(c,oc)) end)
end;

val infiniteprimes =
   let port c and c' in (from(2,c) & p(c,c')) end;


(* A zero searching algorithm *)

fun ordered(x:real,y) = if x < y then (x,y) else (y,x);

fun l(x,y) = x + (y-x)*0.382 and r(x,y) = x + (y-x)*0.618;

fun p(id,f,x,ic,oc) =
   let val v = f(x) 
    in (print(id:string); print(": "); print(x:real); print(" ");
        print(v:real); print("\n");
        oc out (x,f(x)) => ic inp x' => p(id,f,x',ic,oc))
   end;

fun IntHandler(ic1,oc1,ic2,oc2,res,A,B,f,eps) =
   let fun Int(A,B,a,b) =
      let val (A', B') = ordered(A,B) 
       in if (B'-A') <= eps then res out A => NIL
          else let val (A'',B'') = (l(A,B),r(A,B)) 
                in   (ic1 inp (X,x) =>
                        if X = A''
                        then if x * a <= 0.0
                             then oc1 out (l(A,A'')) => Int(A,A'',a,x)
                             else oc1 out (l(B,A'')) => Int(B,A'',b,x)
                        else oc1 out A'' => Int(A,B,a,b))
                   + (ic2 inp (Y,y) =>
                        if Y = B''
                        then if y * b <= 0.0
                             then oc2 out (r(B'',B)) => Int(B'',B,y,b)
                             else oc2 out (r(B'',A)) => Int(B'',A,y,a)
                        else oc2 out B'' => Int(A,B,a,b))
               end
      end
    in Int(A,B,f(A),f(B))
   end;
       

fun Sys(A,B,f,eps,res) =
   let port ic1 and ic2 and oc1 and oc2 
    in   p("p1",f,A,ic1,oc1)
       & p("p2",f,B,ic2,oc2)
       & IntHandler(oc1,ic1,oc2,ic2,res,A,B,f,eps)
   end;

fun result(res) = res inp x => (print(x:real); print("\n"); NIL);

fun roots(f,A,B,eps) = 
   let port res in Sys(A,B,f,eps,res) & result(res) end;


(* Card reader/line printer example that tests for randomness *)

fun cdr(req,ret) = req out () => ret inp _ => cdr(req,ret)
and lpr(req,ret) = req out () => ret inp _ => lpr(req,ret);

fun proc(id,cdrreq,cdrret,lprreq,lprret) =
   (cdrreq inp _ => lprreq inp _ => 
      (print(id:string); print("successful\n");
          cdrret out () => lprret out () => 
          proc(id,cdrreq,cdrret,lprreq,lprret)))
 + (lprreq inp _ => cdrreq inp _ => 
      (print(id:string); print("successful\n");
          lprret out () => cdrret out () => 
          proc(id,cdrreq,cdrret,lprreq,lprret)));

val b = let port cdrreq and cdrret and lprreq and lprret in
        proc("P1",cdrreq,cdrret,lprreq,lprret)
      & proc("P2",cdrreq,cdrret,lprreq,lprret)
      & cdr(cdrreq,cdrret)
      & lpr(lprreq,lprret) end;


