Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file lazy_list.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357openCoretype'anode=|Empty|Consof'a*'alazy_listand'alazy_list='anodeLazy.tletrecmapt~f=Lazy.mapt~f:(function|Empty->Empty|Cons(x,xs)->Cons(fx,mapxs~f));;moduleBase:sigtype'at='alazy_listvalempty:unit->'atvalreturn:'a->'atvalmap:[>`Customof'at->f:('a->'b)->'bt]valappend:'at->'at->'atvalconcat:'att->'atvalbind:'at->f:('a->'bt)->'btend=structtype'at='alazy_listletempty()=Lazy.from_valEmptyletreturnx=Lazy.from_val(Cons(x,Lazy.from_valEmpty))letrecappendt1t2=Lazy.mapt1~f:(function|Empty->Lazy.forcet2|Cons(x,xs)->Cons(x,appendxst2));;letrecconcatt=Lazy.mapt~f:(function|Empty->Empty|Cons(x,xs)->Lazy.force(appendx(concatxs)));;letbindm~f=concat(map~fm)letmap=`Custommapendtype'at='aBase.tinclude(Monad.Make(Base):Monad.Swithtype'at:='at)letempty=Base.emptyletappend=Base.appendletconcat=Base.concatletis_emptyt=matchLazy.forcetwith|Cons_->false|Empty->true;;letlengtht=letrecloopnt=matchLazy.forcetwith|Cons(_,t)->loop(n+1)t|Empty->ninloop0t;;letdeconst=matchLazy.forcetwith|Empty->None|Cons(h,t)->Some(h,t);;letconsxt=Lazy.from_val(Cons(x,t))letrecsnoctx=Lazy.mapt~f:(function|Empty->Cons(x,Base.empty())|Cons(y,ys)->Cons(y,snocysx));;letrecfind~ft=matchLazy.forcetwith|Empty->None|Cons(x,xs)->iffxthenSomexelsefind~fxs;;letrecfilter~ft=Lazy.bindt~f:(function|Empty->empty()|Cons(x,xs)->iffxthenconsx(filter~fxs)elsefilter~fxs);;letrecfilter_optt=Lazy.bindt~f:(function|Empty->empty()|Cons(Somex,xs)->consx(filter_optxs)|Cons(None,xs)->filter_optxs);;letrecfilter_map~ft=Lazy.bindt~f:(function|Empty->empty()|Cons(x,xs)->(matchfxwith|Somey->consy(filter_map~fxs)|None->filter_map~fxs));;letrecfold_left~f~initt=matchLazy.forcetwith|Empty->init|Cons(x,xs)->fold_left~fxs~init:(finitx);;letto_rev_listt=fold_leftt~init:[]~f:(funxsx->x::xs)letto_listt=List.rev(to_rev_listt)letfold_right~ft~init=List.fold(to_rev_listt)~init~f:(funab->fba)letrecfoldrt~f~init=Lazy.mapt~f:(function|Empty->init|Cons(x,xs)->fx(foldr~fxs~init));;letrecitert~f=matchLazy.forcetwith|Empty->()|Cons(x,xs)->fx;iter~fxs;;letof_iterator~curr~next~init=letrecloopaccum()=matchcurraccumwith|Somex->Cons(x,Lazy.from_fun(loop(nextaccum)))|None->EmptyinLazy.from_fun(loopinit);;letrecbuild~f~seed=Lazy.from_fun(fun()->matchfseedwith|None->Empty|Some(x,seed)->Cons(x,build~f~seed));;moduleOf_container=structmoduletypeT=sigtype'atvallazy_fold:'at->f:('a->'bLazy.t->'b)->last:'b->'bendmoduleMake(X:T)=structletlazy_list_of_tx=Lazy.from_fun(fun()->X.lazy_foldx~f:(funxseed->Cons(x,seed))~last:Empty);;endendletunfold~f~init=letrecloopaccum()=matchfaccumwith|Somex->Cons(x,Lazy.from_fun(loopx))(*| Some(x) -> Cons(accum, Lazy.from_fun (loop x)) *)|None->EmptyinLazy.from_fun(loopinit);;letuniter~f=letrecloop()=matchf()with|Somex->Cons(x,Lazy.from_funloop)|None->EmptyinLazy.from_funloop;;letrecof_listxs=Lazy.from_fun(fun()->matchxswith|[]->Empty|x::xs->Cons(x,of_listxs));;letconcat_listt=concat(mapt~f:of_list)letof_arrayary=letrecloopi()=ifi<Array.lengtharythenCons(ary.(i),Lazy.from_fun(loop(succi)))elseEmptyinLazy.from_fun(loop0);;letrecnthxsi=ifi<0thenNoneelse(matchLazy.forcexswith|Empty->None|Cons(x,xs)->ifi=0thenSomexelsenthxs(i-1));;letto_arrayt=matchLazy.forcetwith|Empty->[||]|Cons(x,xs)->letary=Array.create~len:(lengtht)xinleti=ref1initerxs~f:(funx->ary.(!i)<-x;incri);ary;;letrecmerge~cmpxlstylst=Lazy.bindxlst~f:(function|Empty->ylst|Cons(x,xs)->Lazy.bindylst~f:(function|Empty->xlst|Cons(y,ys)->ifcmpxy<=0thenconsx(merge~cmpxsylst)elseconsy(merge~cmpxlstys)));;letrecunify~cmpxlstylst=Lazy.bindxlst~f:(function|Empty->mapylst~f:(funy->`Righty)|Cons(x,xs)->Lazy.bindylst~f:(function|Empty->mapxlst~f:(funx->`Leftx)|Cons(y,ys)->(matchcmpxywith|-1->cons(`Leftx)(unify~cmpxsylst)|0->cons(`Both(x,y))(unify~cmpxsys)|1->cons(`Righty)(unify~cmpxlstys)|_->assertfalse)));;letlazy_sort~cmpzlst=(* This is a stable, O(N log N) worst-case, merge sort. It has the
* additional useful property that forcing the first element only takes
* O(N) time, and forcing each additional element only takes O(log N)
* time, meaning it is worthwhile to sort a lazy list even if you only
* want the first few elements.
*
* The basic strategy is as follows: we convert the lazy list into a
* (normal) list of one element long lazy lists. We then go through
* merging pairs of lazy lists together, into 2 element long lazy lists,
* then 4 element long lazy lists, etc., until we merge all the lists
* back into one big list (that is now in sorted order).
*
* In building the final list, we end up creating about 2N intermediate
* lists (2N-1, I think). Forcing the first element forces the first
* element of all of these lists, meaning that it is O(N) cost to do so.
* But we only remove the heads of O(log N) of these lists (those lists
* whose head element is the head element of the sorted list)- so forcing
* the second element only takes O(log N) work. And so on for the third
* element, etc.
*)letrecto_zlist_listaccum=function|Empty->accum|Cons(x,xs)->to_zlist_list(returnx::accum)(Lazy.forcexs)inletrecmerge_pairsreversedaccum=function|x1::x2::xs->ifreversedthenmerge_pairsreversed(merge~cmpx2x1::accum)xselsemerge_pairsreversed(merge~cmpx1x2::accum)xs|[x]->x::accum|[]->accuminletrecmerge_all_pairsreversed=function|[]->empty()|[x]->x|lst->merge_all_pairs(notreversed)(merge_pairsreversed[]lst)inmerge_all_pairstrue(to_zlist_list[](Lazy.forcezlst));;letsort~cmpzlst=(* We inline to_array here, so we can control where we catch the
* invalid_argument exception Array.create ~len:throws when we try to
* make too large of an array.
*)matchLazy.forcezlstwith|Empty->zlst|Cons(x,xs)->(* Note, a little convolution is necessary here, as I want to trap
* Invalid_argument exceptions *only* around the Array.create ~len:call.
* Remember that iterating through the lazy list is potientially
* executing code that could potientially throw Invalid_argument
* for entirely other reasons, and I don't want to catch those
* exceptions.
*)letary_opt=trySome(Array.create~len:(lengthzlst)x)with|Invalid_argument_->Nonein(matchary_optwith|None->(* Array was too large- abort to lazy_sort *)lazy_sort~cmpzlst|Someary->(* Fill the array *)leti=ref1initerxs~f:(funx->ary.(!i)<-x;incri);(* Sort the array *)Array.sort~compare:cmpary;(* Return the lazy list of the array *)of_arrayary);;moduleIterator=structtype'alazy_list='attype'at='alazy_listrefletcreatezlst=refzlstletnextt=matchdecons!twith|Some(hd,tl)->t:=tl;Somehd|None->None;;letitert~f=letrecloop()=matchnexttwith|Someitem->fitem;loop()|None->()inloop();;end(* cartesian_product : [[a]] -> [[a]] *)letreccartesian_productt=matchLazy.forcetwith|Empty->return(empty())|Cons(xs,xss)->xs>>=funy->cartesian_productxss>>=funys->return(consyys);;