123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679(* This file is free software, part of containers. See file "license" for more details. *)type'aiter=('a->unit)->unittype'agen=unit->'aoptiontype'aequal='a->'a->booltype'aord='a->'a->inttype'aprinter=Format.formatter->'a->unitincludeSeqletnil()=Nil[@@@iflt4.11]letconsab()=Cons(a,b)[@@@endif][@@@iflt5.4]letsingletonx()=Cons(x,nil)[@@@endif][@@@iflt4.14]letinitnf=letrecauxi()=ifi>=nthenNilelseCons (fi,aux(i+1))inaux0[@@@endif]letrec_foreverx()=Cons(x,_foreverx)letrec_repeatnx()=ifn<=0thenNilelseCons(x,_repeat(n-1)x)letrepeat?nx=matchnwith|None->_foreverx|Somen->_repeatnxletrecforeverf()=Cons(f(),foreverf)[@@@iflt4.14]letis_emptyl=matchl()with|Nil->true|Cons_->false[@@@endif]lethead_exnl=matchl()with|Nil->raiseNot_found|Cons(x,_)->xletheadl=matchl()with|Nil->None|Cons(x,_)->Somexlettail_exnl=matchl()with|Nil-> raiseNot_found|Cons(_,l)->llettaill=matchl()with|Nil->None|Cons(_,l)->Somel[@@@iflt4.14]letunconsl=matchl()with|Nil->None|Cons(h,t)->Some(h,t)[@@@endif]letrecequaleql1l2=match l1(),l2()with|Nil,Nil->true|Nil,_|_,Nil->false|Cons (x1,l1'),Cons (x2,l2')->eqx1x2&&equaleql1'l2'letreccomparecmpl1l2=matchl1(),l2()with|Nil,Nil->0|Nil,_->-1|_,Nil->1|Cons (x1,l1'),Cons(x2,l2')->letc=cmpx1x2inifc=0thencomparecmpl1'l2'elsecletrecfoldfaccres=matchres()with|Nil->acc|Cons(s,cont)->foldf(faccs)contletfold_left=foldletfoldifaccres=letrecauxaccires=matchres()with|Nil->acc|Cons(s,cont)->aux(faccis)(i+1)continauxacc0res[@@@iflt4.14]letfold_lefti=foldiletiterifl=letrecauxfli=match l()with|Nil->()|Cons (x,l')->fix;auxfl'(i+1)inauxfl0letlengthl=fold(funacc_->acc+1)0lletrectaken(l:'at)()=ifn=0thenNilelse(matchl()with|Nil->Nil|Cons(x,l')->Cons(x,take(n-1)l'))letrectake_whilepl()=matchl()with|Nil->Nil|Cons(x,l')->ifpxthenCons(x,take_while pl')elseNilletrecdropn(l:'at)()=matchl()with|l'whenn=0->l'|Nil->Nil|Cons (_,l')->drop(n-1)l'()letrecdrop_whilepl()=matchl()with|Nil->Nil|Cons(x,l')whenpx->drop_whilepl'()|Cons_asres->resletmapifl=letrecauxfli()=matchl()with|Nil ->Nil|Cons(x,tl)->Cons(fix,auxftl(i+1))inauxfl0[@@@endif][@@@iflt5.4]letfilterifl=letrecauxfli()=matchl()with|Nil->Nil|Cons(x,tl)->iffixthenCons(x,auxftl(i+1))elseauxftl(i+1)()inauxfl0[@@@endif]letfmap=filter_map[@@@iflt4.11]letrecappendl1l2()=matchl1()with|Nil->l2()|Cons(x,l1')->Cons(x,appendl1'l2)[@@@endif][@@@iflt4.14]letreccyclel=ifis_emptylthenlelsefun()->appendl(cycle l)()letreciteratefa()=Cons(a,iterate f(fa))[@@@endif][@@@iflt4.11]letrecunfoldfacc()=matchfaccwith|None->Nil|Some(x,acc')->Cons(x,unfoldfacc')[@@@endif][@@@iflt4.14]letrecfor_allpl=match l()with|Nil->true|Cons(x,tl)->px&& for_allptlletrecexistspl=matchl()with|Nil->false|Cons(x,tl)->px||existsptlletrecfindpl=match l()with|Nil->None|Cons(x,tl)->ifpxthenSomexelsefindptlletrecfind_mapfl=matchl()with|Nil->None|Cons(x,tl)->(matchfxwith|None->find_mapftl|e->e)[@@@endif][@@@iflt5.1]letfind_indexpl=letrecauxil=matchl()with|Nil->None|Cons(x,tl)->ifpxthenSomeielseaux(i+1)tlinaux0lletfind_mapifl=letrecauxil=matchl()with|Nil->None|Cons(x,tl)->(matchfixwith|Some_asres->res|None->aux(i+1)tl)inaux0l[@@@endif][@@@iflt5.1]letrecscanfaccres()=Cons(acc,fun()->matchres()with|Nil->Nil|Cons(s,cont)->scanf(faccs)cont())[@@@endif][@@@iflt4.13]letconcat_map=flat_map[@@@endif]letproduct_withfl1l2=letrec_next_lefth1tl1h2tl2()=matchtl1()with|Nil->_next_right~die:trueh1tl1h2tl2()|Cons(x,tl1')->_map_list_leftxh2(_next_right~die:false(x::h1)tl1'h2tl2)()and _next_right~dieh1tl1h2tl2()=matchtl2()with|Nilwhendie->Nil|Nil->_next_lefth1tl1 h2tl2()|Cons(y,tl2')->_map_list_righth1y(_next_lefth1tl1(y::h2)tl2')()and_map_list_leftxlkont()=matchlwith|[]->kont()|y::l'->Cons(fxy,_map_list_leftxl'kont)and_map_list_rightlykont()=matchlwith|[]->kont()|x::l'->Cons(fxy,_map_list_rightl' ykont)in_next_left[]l1[]l2[@@@iflt4.14]letmap_product =product_withletproductl1l2=product_with(funxy->x,y)l1l2letrecgroupeql()=matchl()with|Nil->Nil|Cons(x,l')->Cons(consx(take_while(eqx)l'),groupeq(drop_while(eqx)l'))[@@@endif]letrec_uniqeqprevl()=matchprev,l()with|_,Nil->Nil|None,Cons(x,l')->Cons(x,_uniqeq(Somex)l')|Somey,Cons (x,l')->ifeqxythen_uniqeqprevl'()elseCons(x,_uniq eq(Somex)l')letuniqeql=_uniqeqNonel[@@@iflt4.13]letconcatl=flat_map(funx->x)l[@@@endif]letflatten=concatletrangeij=letrecauxij()=ifi=jthenCons(i,nil)elseifi<jthenCons(i,aux(i+1)j)elseCons(i,aux(i-1)j)inauxijlet(--)=rangelet(--^)ij=ifi=jthenemptyelseifi<jthenrangei(j-1)elserangei(j+1)[@@@iflt4.14]letrecfold_left2faccl1l2=matchl1(),l2()with|Nil,_|_,Nil->acc|Cons(x1,l1'),Cons(x2,l2')->fold_left2f(faccx1x2)l1'l2'[@@@endif]letfold2=fold_left2[@@@iflt4.14]letrecmap2fl1l2()=matchl1(),l2()with|Nil,_|_,Nil->Nil|Cons(x1,l1'),Cons(x2,l2')->Cons(fx1x2,map2fl1'l2')letreciter2fl1l2=matchl1(),l2()with|Nil,_|_,Nil->()|Cons(x1,l1'),Cons(x2,l2')->fx1x2;iter2fl1'l2'letrecfor_all2fl1l2=matchl1(),l2()with|Nil,_|_,Nil->true|Cons(x1,l1'),Cons(x2,l2')->fx1x2&&for_all2fl1'l2'letrecexists2fl1 l2=matchl1(),l2()with|Nil,_|_,Nil->false|Cons(x1,l1'),Cons(x2,l2')->fx1x2||exists2fl1'l2'letrecsorted_mergecmpl1l2()=matchl1(),l2()with|Nil,tl2->tl2|tl1,Nil-> tl1|Cons (x1,l1'),Cons(x2,l2')->ifcmpx1x2<0thenCons(x1,sorted_mergecmpl1'l2)elseCons(x2,sorted_mergecmpl1l2')[@@@endif]let merge=sorted_merge[@@@iflt4.14]let reczipab()=matcha(),b()with|Nil,_|_,Nil->Nil|Cons(x,a'),Cons(y,b')->Cons((x,y),zipa'b')letunzipl=letrecfirstl()=match l()with|Nil->Nil|Cons((x,_),tl)->Cons(x,firsttl)andsecondl()=matchl()with|Nil->Nil|Cons((_,y),tl)->Cons(y,second tl)infirstl,secondlletsplit=unzip[@@@endif]letzip_i seq=letrecloop iseq()=matchseq()with|Nil->Nil|Cons(x,tl)->Cons((i,x),loop(i+1)tl)inloop0seq(** {2 Implementations} *)letpure=returnlet(>>=)xsf=flat_mapfxslet(>|=)xsf=mapfxslet(<*>)fsxs=product_with(funfx->fx)fsxs(** {2 Conversions} *)letrec_to_rev_listaccl=matchl()with|Nil->acc|Cons(x,l')->_to_rev_list(x::acc)l'letto_rev_listl=_to_rev_list[]lletto_listl=letrecdirecti(l:'at)=matchl()with|Nil->[]|_wheni=0->List.rev(_to_rev_list[]l)|Cons(x,f)->x::direct(i-1)findirect200lletof_listl=letrecauxl()=matchlwith|[]->Nil|x::l'->Cons(x,auxl')inauxlletof_arraya=letrecauxai()=ifi=Array.lengthathenNilelseCons(a.(i),auxa(i+1))inauxa0letof_strings=letrecauxsi()=ifi=String.lengthsthenNilelseCons(String.getsi,auxs(i+1))inauxs0letto_arrayl=(* We contruct the length and list of seq elements (in reverse) in one pass *)letlen=ref0inletls=fold_left(funaccx->incrlen;x::acc)[]lin(* The length is used to initialize the array, and then to derive the index for
each item, working back from the last. This lets us only traverse the list
twice, instead of having to reverse it. *)matchlswith|[]->[||]|init::rest->leta=Array.make!leninitin(* Subtract 1 for len->index conversion and 1 for the removed [init] *)letidx=!len-2inignore(List.fold_left(funix->a.(i)<-x;i-1)idxrest:int);aletrecto_iterresk=matchres()with|Nil->()|Cons(s,f)->ks;to_iterfkletto_genl=letl=reflinfun()->match!l()with|Nil->None|Cons(x,l')->l:=l';Somextype'aof_gen_state=|Of_gen_thunkof'agen|Of_gen_savedof'anodeletof_geng=letrecconsumer()=match!rwith|Of_gen_savedcons->cons|Of_gen_thunkg->(matchg()with|None->r:=Of_gen_savedNil;Nil|Somex->lettl=consume(ref(Of_gen_thunkg))inletl=Cons(x,tl)inr:=Of_gen_savedl;l)inconsume(ref(Of_gen_thunkg))letsort~cmpl=letl=to_listlinof_list(List.sortcmpl)letsort_uniq~cmpl=letl=to_listlinuniq(funxy->cmpxy=0)(of_list(List.sortcmpl))type'amemoize=|MemoThunk|MemoSaveof'anodeletrecmemoizef=letr=refMemoThunkinfun()->match!rwith|MemoSavel->l|MemoThunk->letl=matchf()with|Nil->Nil|Cons(x,tail)->Cons(x,memoizetail)inr:=MemoSavel;l(** {2 Fair Combinations} *)[@@@iflt4.14]letrecinterleaveab()=matcha()with|Nil->b()|Cons(x,tail)->Cons(x,interleavebtail)[@@@endif]letrecfair_flat_mapfa()=matcha()with|Nil->Nil|Cons(x,tail)->lety=fxininterleavey(fair_flat_mapftail)()letrecfair_appfa()=matchf()with|Nil->Nil|Cons(f1,fs)->interleave(mapf1a)(fair_appfsa)()let(>>-)af=fair_flat_mapfalet(<.>)fa=fair_appfa(** {2 Infix} *)moduleInfix=structlet(>>=)=(>>=)let(>|=)=(>|=)let(<*>)=(<*>)let(>>-)=(>>-)let(<.>)=(<.>)let(--)=(--)let(--^)=(--^)end(** {2 Monadic Operations} *)moduletypeMONAD=sigtype'atvalreturn:'a->'atval(>>=):'at->('a->'bt)->'btendmoduleTraverse(M:MONAD)=structopenMletmap_mfl=letrecauxaccl=matchl()with|Nil->return(of_list(List.revacc))|Cons(x,l')->fx>>=funx'->aux(x'::acc)l'inaux[]lletsequence_ml=map_m(funx->x)lletrecfold_mfaccl=matchl()with|Nil->returnacc|Cons(x,l')->faccx>>=funacc'->fold_mfacc'l'end(** {2 IO} *)letpp?(pp_start=fun_()->())?(pp_stop=fun_()->())?(pp_sep=funout()->Format.fprintfout",@ ")pp_itemfmtl=pp_startfmt();letrecppfmtl=matchl()with|Nil->()|Cons(x,l')->pp_sepfmt();Format.pp_print_cutfmt();pp_itemfmtx;ppfmtl'in(matchl()with|Nil->()|Cons(x,l')->pp_itemfmtx;ppfmtl');pp_stopfmt()