123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266openElements(*
+---------+ +---------+ +---------+
| | | | | |
... --> node0 --> i --> node1 --> o --> nnde2 --> ...
| | | | | |
+----|----+ +----|----+ +----|----+
v v v
... r ...
*)(* Core Types *)type('i,'o,'r)node=|Yieldof('o*('i,'o,'r)nodelazy_t)|Awaitof('i->('i,'o,'r)node)|Readyof'r(* Type Synonyms *)(* 'Effect's neither `await` nor `yield`. *)type'reffect=(void,void,'r)node(* 'Producer's can only `yield`. *)type('o,'r)producer=(void,'o,'r)node(* 'Consumer's can only `await`. *)type('i,'r)consumer=('i,void,'r)node(* Monad *)letreturnr=Readyrletrec(>>=)nf=matchnwith|Yield(b,lazyn')->Yield(b,lazy(n'>>=f))|Awaitk->Await(funa->ka>>=f)|Readyr->frlet(>>)n1n2=n1>>=fun_->!n2letrecforeverm=m>>lazy(foreverm)letrecreplicatenm=ifn<0thenraise(Invalid_argument"replicate: negative index")elseifn=0thenreturn()elsem>>lazy(replicate(n-1)m)(* Creation *)letempty=Ready()letyieldb=Yield(b,lazyempty)letawait=Await(funb->Readyb)(* Category *)letrecid=Await(funa->Yield(a,lazyid))(* let rec id () = await >>= fun a -> yield a >> lazy (id ()) *)letreccomposedu=matchd,uwith(* Downstream is ready & upstream still yielding: notify the upstream about termination. *)|Readyr,Yield_->Readyr|Readyr,Await_->Readyr|Readyr,Ready_->Readyr|Yield(b,d'),_->yieldb>>lazy(compose!d'u)|Awaitk,Yield(b,u')->compose(kb)!u'|Await_,Awaitk->await>>=funa->composed(ka)(* Upstream is ready & downstream is still awaiting: notify downstream about termination. *)|Await_,Readyr->Readyrlet(<<<)n1n2=composen1n2let(>>>)n2n1=composen1n2(* Helper Operations *)letrecrunn=matchnwith|Readyr->r|Awaitk->run(kVoid)|Yield(a,lazyn')->runn'letnextnode=matchnodewith|Ready_->None|Yield(a,lazys')->Some(a,s')|Awaitk->fail"Node requires more input."moduleSeq:sigval(=>):('a,'b,'r)node->('b,'c,'r)node->('a,'c,'r)nodeval(<=):('b,'c,'r)node->('a,'b,'r)node->('a,'c,'r)nodevalcount:(void,int,'r)nodevalnth:int->('a,'b,'r)node->'boptionvalmap:('a->'b)->('a,'b,'r)nodevalfilter:('a->bool)->('a,'a,'r)nodevaltake:int->('a,'a,unit)nodevaltake_while:('a->bool)->('a,'a,unit)nodevaldrop:int->('a,'a,'b)nodevaldrop_while:('a->bool)->('a,'a,'b)nodevaltail:('a,'a,'b)nodevalrepeat:?n:int->'a->('b,'a,unit)nodevaliota:int->(void,int,unit)nodevalslice:int->int->('a,'a,unit)nodevalrange:int->int->(void,int,unit)nodevalfold:init:'a->f:('a->'b->'a)->('c,'b,'d)node->'avalsum:(void,int,'r)node->intvallen:(void,int,'r)node->intvalany:(void,bool,'r)node->boolvallast:(void,'b,'r)node->'boptionvalhead:(void,'b,'r)node->'boptionvallist:'alist->(void,'a,unit)nodevalfile:string->(void,string,unit)nodevalcollect:('a,'b,'c)node->'blistend=structlet(=>)=(>>>)let(<=)=(<<<)letreccount=letrecloopn=yieldn>>lazy(loop(n+1))inloop0letrecmap_recf=await>>=funa->yield(fa)>>lazy(map_recf)letmap_foreverf=forever(await>>=funa->yield(fa))letmap=map_foreverletrecfilterpred=await>>=funa->ifpredathenyielda>>lazy(filterpred)elsefilterpredletrectake_recn=ifn<0thenraise(Invalid_argument"take: negative index")elseifn=0thenreturn()elseawait>>=funi->yieldi>>lazy(take_rec(n-1))lettake_replicaten=replicaten(await>>=yield)lettake=take_replicateletrectake_whilepred=await>>=funa->ifpredathenyielda>>lazy(take_whilepred)elsereturn()letrecdropn=ifn=0thenidelseawait>>=funa->drop(n-1)letrecdrop_whilepred=await>>=funa->ifpredathendrop_whilepredelseidlettail=Await(fun_->id)letrecrepeat?nx=matchnwith|Somen->replicaten(yieldx)|None->forever(yieldx)letreciotastop=count>>>takestopletrangestartstop=count>>>takestop>>>dropstartletsliceij=dropi>>>take(j-i)letfold~init~fsource=letrecloopsourceacc=matchnextsourcewith|Some(a,rest)->looprest(facca)|None->accinloopsourceinitletnth_directnsource=ifn<0thenfail"nth: negative index"elseletrecloopnsource=matchnextsourcewith|Some(a,rest)->ifn=0thenSomeaelseloop(n-1)rest|None->Noneinloopnsourceletnth=nth_directletheadp=matchnextpwith|Some(a,_)->Somea|None->Noneletsumsource=fold~init:0~f:(+)sourceletlensource=fold~init:0~f:(funci->c+1)sourceletrecanysource=matchnextsourcewith|Some(a,_)whena->a|Some(a,rest)->anyrest|None->falseletlastsource=letreclooplast_optsource=matchnextsourcewith|Some(a,rest)->loop(Somea)rest|None->last_optinloopNonesourceletreclistxs=matchxswith|x::xs'->yieldx>>lazy(listxs')|[]->return()letrecfilefile_path=letc=open_infile_pathinletrecloop()=yield(input_linec)>>lazy(loop())intryloop()withEnd_of_file->return()letcollectsrc=letrecloopsrcacc=matchnextsrcwith|Some(a,rest)->looprest(a::acc)|None->List.revaccinloopsrc[]endmoduleTest=structopenSeqlettest_slice()=beginassert(collect(count=>Seq.slice38)=[3;4;5;6;7]);endletapi()=begin(* Compute the sum of all odd integers up to 1000000. *)assert(fold~init:0~f:(+)(iota1000000=>filterodd)=250000000000);(* Take 5 integers from an infinit sequence and collect them into a list. *)assert(collect(count=>take5)=[0;1;2;3;4]);endend