1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)type'acmp='a->'a->inttype'aeq='a->'a->boolmoduletypeS=moduletypeofListmoduletypeExtS=sigincludeSvalcompare:'acmp->'alistcmpvalequal:'aeq->'alisteqvalis_empty:'alist->boolvalmem_f:'aeq->'a->'alist->boolvalfor_all_i:(int->'a->bool)->int->'alist->boolvalfor_all2eq:('a->'b->bool)->'alist->'blist->boolvalprefix_of:'aeq->'alist->'alist->boolvalsame_length:'alist->'blist->boolvalinterval:int->int->intlistvalmake:int->'a->'alistvaladdn:int->'a->'alist->'alistvalinit:int->(int->'a)->'alistvalappend:'alist->'alist->'alistvalconcat:'alistlist->'alistvalflatten:'alistlist->'alistvalassign:'alist->int->'a->'alistvalfilter:('a->bool)->'alist->'alistvalfilter2:('a->'b->bool)->'alist->'blist->'alist*'blistvalfilteri:(int->'a->bool)->'alist->'alistvalfilter_with:boollist->'alist->'alistvalmap_filter:('a->'boption)->'alist->'blistvalmap_filter_i:(int->'a->'boption)->'alist->'blistvalpartitioni:(int->'a->bool)->'alist->'alist*'alistvalmap:('a->'b)->'alist->'blistvalmap2:('a->'b->'c)->'alist->'blist->'clistvalmap_left:('a->'b)->'alist->'blistvalmap_i:(int->'a->'b)->int->'alist->'blistvalmap2_i:(int->'a->'b->'c)->int->'alist->'blist->'clistvalmap3:('a->'b->'c->'d)->'alist->'blist->'clist->'dlistvalmap4:('a->'b->'c->'d->'e)->'alist->'blist->'clist->'dlist->'elistvalmap_of_array:('a->'b)->'aarray->'blistvalmap_append:('a->'blist)->'alist->'blistvalmap_append2:('a->'b->'clist)->'alist->'blist->'clistvalextend:boollist->'a->'alist->'alistvalcount:('a->bool)->'alist->intvalindex:'aeq->'a->'alist->intvalsafe_index:'aeq->'a->'alist->intoptionvalindex0:'aeq->'a->'alist->intvalfold_left_until:('c->'a->'cCSig.until)->'c->'alist->'cvalfold_right_i:(int->'a->'b->'b)->int->'alist->'b->'bvalfold_left_i:(int->'a->'b->'a)->int->'a->'blist->'avalfold_right_and_left:('a->'b->'blist->'a)->'blist->'a->'avalfold_left3:('a->'b->'c->'d->'a)->'a->'blist->'clist->'dlist->'avalfold_left2_set:exn->('a->'b->'c->'blist->'clist->'a)->'a->'blist->'clist->'avalfold_left_map:('a->'b->'a*'c)->'a->'blist->'a*'clistvalfold_right_map:('b->'a->'c*'a)->'blist->'a->'clist*'avalfold_left2_map:('a->'b->'c->'a*'d)->'a->'blist->'clist->'a*'dlistvalfold_right2_map:('b->'c->'a->'d*'a)->'blist->'clist->'a->'dlist*'avalfold_left3_map:('a->'b->'c->'d->'a*'e)->'a->'blist->'clist->'dlist->'a*'elistvalfold_left4_map:('a->'b->'c->'d->'e->'a*'r)->'a->'blist->'clist->'dlist->'elist->'a*'rlistvalexcept:'aeq->'a->'alist->'alistvalremove:'aeq->'a->'alist->'alistvalremove_first:('a->bool)->'alist->'alistvalextract_first:('a->bool)->'alist->'alist*'avalfind_map:('a->'boption)->'alist->'bexceptionIndexOutOfRangevalgoto:int->'alist->'alist*'alistvalsplit_when:('a->bool)->'alist->'alist*'alistvalsep_last:'alist->'a*'alistvaldrop_last:'alist->'alistvallast:'alist->'avallastn:int->'alist->'alistvalchop:int->'alist->'alist*'alistvalfirstn:int->'alist->'alistvalskipn:int->'alist->'alistvalskipn_at_least:int->'alist->'alistvaldrop_prefix:'aeq->'alist->'alist->'alistvalinsert:('a->'a->bool)->'a->'alist->'alistvalshare_tails:'alist->'alist->'alist*'alist*'alistvalmap_assoc:('a->'b)->('c*'a)list->('c*'b)listvalassoc_f:'aeq->'a->('a*'b)list->'bvalremove_assoc_f:'aeq->'a->('a*'b)list->('a*'b)listvalmem_assoc_f:'aeq->'a->('a*'b)list->boolvalfactorize_left:'aeq->('a*'b)list->('a*'blist)listvalsplit:('a*'b)list->'alist*'blistvalcombine:'alist->'blist->('a*'b)listvalsplit3:('a*'b*'c)list->'alist*'blist*'clistvalsplit4:('a*'b*'c*'d)list->'alist*'blist*'clist*'dlistvalcombine3:'alist->'blist->'clist->('a*'b*'c)listvaladd_set:'aeq->'a->'alist->'alistvaleq_set:'aeq->'alist->'alist->boolvalsubset:'alist->'alist->boolvalmerge_set:'acmp->'alist->'alist->'alistvalintersect:'aeq->'alist->'alist->'alistvalunion:'aeq->'alist->'alist->'alistvalunionq:'alist->'alist->'alistvalsubtract:'aeq->'alist->'alist->'alistvalsubtractq:'alist->'alist->'alistvaldistinct:'alist->boolvaldistinct_f:'acmp->'alist->boolvalduplicates:'aeq->'alist->'alistvaluniquize:'alist->'alistvalsort_uniquize:'acmp->'alist->'alistvalmin:'acmp->'alist->'avalcartesian:('a->'b->'c)->'alist->'blist->'clistvalcartesians:('a->'b->'b)->'b->'alistlist->'blistvalcombinations:'alistlist->'alistlistvalcartesians_filter:('a->'b->'boption)->'b->'alistlist->'blistmoduleSmart:sigvalmap:('a->'a)->'alist->'alistendmoduletypeMonoS=sigtypeeltvalequal:eltlist->eltlist->boolvalmem:elt->eltlist->boolvalassoc:elt->(elt*'a)list->'avalmem_assoc:elt->(elt*'a)list->boolvalremove_assoc:elt->(elt*'a)list->(elt*'a)listvalmem_assoc_sym:elt->('a*elt)list->boolendendincludeList(** Tail-rec implementation of usual functions. This is a well-known trick used
in, for instance, ExtLib and Batteries. *)type'acell={head:'a;mutabletail:'alist;}externalcast:'acell->'alist="%identity"(** Extensions and redefinitions of OCaml Stdlib *)(** {6 Equality, testing} *)letrecsame_lengthl1l2=matchl1,l2with|[],[]->true|_::l1,_::l2->same_lengthl1l2|([],_::_)|(_::_,[])->falseletreccomparecmpl1l2=ifl1==l2then0elsematchl1,l2with|[],[]->0|_::_,[]->1|[],_::_->-1|x1::l1,x2::l2->matchcmpx1x2with|0->comparecmpl1l2|c->cletrecequalcmpl1l2=l1==l2||matchl1,l2with|[],[]->true|x1::l1,x2::l2->cmpx1x2&&equalcmpl1l2|_->falseletis_empty=function|[]->true|_->falseletmem_fcmpxl=List.exists(cmpx)lletfor_all_ip=letrecfor_all_pi=function|[]->true|a::l->pia&&for_all_p(i+1)linfor_all_pletfor_all2eqfl1l2=tryList.for_all2fl1l2withInvalid_argument_->falseletprefix_ofcmpprefll=letrecprefrec=function|(h1::t1,h2::t2)->cmph1h2&&prefrec(t1,t2)|([],_)->true|_->falseinprefrec(prefl,l)(** {6 Creating lists} *)letintervalnm=letrecinterval_n(l,m)=ifn>mthenlelseinterval_n(m::l,predm)ininterval_n([],m)letaddnnv=letrecauxnl=ifInt.equaln0thenlelseaux(predn)(v::l)inifn<0theninvalid_arg"List.addn"elseauxnletmakenv=addnnv[]letrecinit_looplenfpi=ifInt.equalilenthen()elseletc={head=fi;tail=[]}inp.tail<-castc;init_looplenfc(succi)letinitlenf=iflen<0theninvalid_arg"List.init"elseifInt.equallen0then[]elseletc={head=f0;tail=[]}ininit_looplenfc1;castcletrecappend_loopptl=function|[]->p.tail<-tl|x::l->letc={head=x;tail=[]}inp.tail<-castc;append_loopctllletappendl1l2=matchl1with|[]->l2|x::l->letc={head=x;tail=[]}inappend_loopcl2l;castcletreccopyp=function|[]->p|x::l->letc={head=x;tail=[]}inp.tail<-castc;copyclletrecconcat_loopp=function|[]->()|x::l->concat_loop(copypx)lletconcatl=letdummy={head=Obj.magic0;tail=[]}inconcat_loopdummyl;dummy.tailletflatten=concat(** {6 Lists as arrays} *)letassignlne=letrecassrecstkli=matchl,iwith|(h::t,0)->List.rev_appendstk(e::t)|(h::t,n)->assrec(h::stk)t(predn)|([],_)->failwith"List.assign"inassrec[]ln(** {6 Filtering} *)letrecfilter_loopfp=function|[]->()|x::l'asl->letb=fxinfilter_loopfpl';ifbthenifp.tail==l'thenp.tail<-lelsep.tail<-x::p.tailletrecfilterf=function|[]->[]|x::l'asl->iffxthenletc={head=x;tail=[]}infilter_loopfcl';ifc.tail==l'thenlelsecastcelsefilterfl'letrecfilter2_loopfpql1l2=matchl1,l2with|[],[]->()|x::l1',y::l2'->letb=fxyinfilter2_loopfpql1'l2';ifbthenifp.tail==l1'thenbeginp.tail<-l1;q.tail<-l2endelsebeginp.tail<-x::p.tail;q.tail<-y::q.tailend|_->invalid_arg"List.filter2"letrecfilter2fl1l2=matchl1,l2with|[],[]->([],[])|x1::l1',x2::l2'->letb=fx1x2inifbthenletc1={head=x1;tail=[]}inletc2={head=x2;tail=[]}infilter2_loopfc1c2l1'l2';ifc1.tail==l1'then(l1,l2)else(castc1,castc2)elsefilter2fl1'l2'|_->invalid_arg"List.filter2"letfilterip=letrecfilter_i_reci=function|[]->[]|x::l->letl'=filter_i_rec(succi)linifpixthenx::l'elsel'infilter_i_rec0letrecfilter_with_loopfilterpl=matchfilter,lwith|[],[]->()|b::filter,x::l'->filter_with_loopfilterpl';ifbthenifp.tail==l'thenp.tail<-lelsep.tail<-x::p.tail|_->invalid_arg"List.filter_with"letrecfilter_withfilterl=matchfilter,lwith|[],[]->[]|b::filter,x::l'->ifbthenletc={head=x;tail=[]}infilter_with_loopfiltercl';ifc.tail==l'thenlelsecastcelsefilter_withfilterl'|_->invalid_arg"List.filter_with"letrecmap_filter_loopfp=function|[]->()|x::l->matchfxwith|None->map_filter_loopfpl|Somey->letc={head=y;tail=[]}inp.tail<-castc;map_filter_loopfclletrecmap_filterf=function|[]->[]|x::l'->matchfxwith|None->map_filterfl'|Somey->letc={head=y;tail=[]}inmap_filter_loopfcl';castcletrecmap_filter_i_loopfip=function|[]->()|x::l->matchfixwith|None->map_filter_i_loopf(succi)pl|Somey->letc={head=y;tail=[]}inp.tail<-castc;map_filter_i_loopf(succi)clletrecmap_filter_i_loop'fi=function|[]->[]|x::l'->matchfixwith|None->map_filter_i_loop'f(succi)l'|Somey->letc={head=y;tail=[]}inmap_filter_i_loopf(succi)cl';castcletmap_filter_ifl=map_filter_i_loop'f0lletpartitionip=letrecauxi=function|[]->[],[]|x::l->let(l1,l2)=aux(succi)linifpixthen(x::l1,l2)else(l1,x::l2)inaux0(** {6 Applying functorially} *)letrecmap_loopfp=function|[]->()|x::l->letc={head=fx;tail=[]}inp.tail<-castc;map_loopfclletmapf=function|[]->[]|x::l->letc={head=fx;tail=[]}inmap_loopfcl;castcletrecmap2_loopfpl1l2=matchl1,l2with|[],[]->()|x::l1,y::l2->letc={head=fxy;tail=[]}inp.tail<-castc;map2_loopfcl1l2|_->invalid_arg"List.map2"letmap2fl1l2=matchl1,l2with|[],[]->[]|x::l1,y::l2->letc={head=fxy;tail=[]}inmap2_loopfcl1l2;castc|_->invalid_arg"List.map2"(** Like OCaml [List.mapi] but tail-recursive *)letrecmap_i_loopfip=function|[]->()|x::l->letc={head=fix;tail=[]}inp.tail<-castc;map_i_loopf(succi)clletmap_ifi=function|[]->[]|x::l->letc={head=fix;tail=[]}inmap_i_loopf(succi)cl;castcletmap_left=mapletmap2_ifil1l2=letrecmap_ii=function|([],[])->[]|(h1::t1,h2::t2)->letv=fih1h2inv::map_i(succi)(t1,t2)|(_,_)->invalid_arg"map2_i"inmap_ii(l1,l2)letrecmap3_loopfpl1l2l3=matchl1,l2,l3with|[],[],[]->()|x::l1,y::l2,z::l3->letc={head=fxyz;tail=[]}inp.tail<-castc;map3_loopfcl1l2l3|_->invalid_arg"List.map3"letmap3fl1l2l3=matchl1,l2,l3with|[],[],[]->[]|x::l1,y::l2,z::l3->letc={head=fxyz;tail=[]}inmap3_loopfcl1l2l3;castc|_->invalid_arg"List.map3"letrecmap4_loopfpl1l2l3l4=matchl1,l2,l3,l4with|[],[],[],[]->()|x::l1,y::l2,z::l3,t::l4->letc={head=fxyzt;tail=[]}inp.tail<-castc;map4_loopfcl1l2l3l4|_->invalid_arg"List.map4"letmap4fl1l2l3l4=matchl1,l2,l3,l4with|[],[],[],[]->[]|x::l1,y::l2,z::l3,t::l4->letc={head=fxyzt;tail=[]}inmap4_loopfcl1l2l3l4;castc|_->invalid_arg"List.map4"letrecmap_of_array_loopfpail=ifInt.equalilthen()elseletc={head=f(Array.unsafe_getai);tail=[]}inp.tail<-castc;map_of_array_loopfca(i+1)lletmap_of_arrayfa=letl=Array.lengthainifInt.equall0then[]elseletc={head=f(Array.unsafe_geta0);tail=[]}inmap_of_array_loopfca1l;castcletmap_appendfl=flatten(mapfl)letmap_append2fl1l2=flatten(map2fl1l2)letrecextendlal'=matchl,l'with|true::l,b::l'->b::extendlal'|false::l,l'->a::extendlal'|[],[]->[]|_->invalid_arg"extend"letcountfl=letrecauxacc=function|[]->acc|h::t->iffhthenaux(acc+1)telseauxacctinaux0l(** {6 Finding position} *)letrecindex_ffxln=matchlwith|[]->raiseNot_found|y::l->iffxythennelseindex_ffxl(succn)letindexfxl=index_ffxl1letsafe_indexfxl=trySome(indexfxl)withNot_found->Noneletindex0fxl=index_ffxl0(** {6 Folding} *)letfold_left_untilfaccus=letrecauxaccu=function|[]->accu|x::xs->matchfaccuxwithCSig.Stopx->x|CSig.Conti->auxixsinauxaccusletfold_right_ifil=letrecit_fila=matchlwith|[]->a|b::l->f(i-1)b(it_f(i-1)la)init_f(List.lengthl+i)lletfold_left_if=letrecit_list_fia=function|[]->a|b::l->it_list_f(i+1)(fiab)linit_list_fletrecfold_left3faccul1l2l3=match(l1,l2,l3)with|([],[],[])->accu|(a1::l1,a2::l2,a3::l3)->fold_left3f(faccua1a2a3)l1l2l3|(_,_,_)->invalid_arg"List.fold_left3"letrecfold_left4faccul1l2l3l4=match(l1,l2,l3,l4)with|([],[],[],[])->accu|(a1::l1,a2::l2,a3::l3,a4::l4)->fold_left4f(faccua1a2a3a4)l1l2l3l4|(_,_,_,_)->invalid_arg"List.fold_left4"(* [fold_right_and_left f [a1;...;an] hd =
f (f (... (f (f hd
an
[an-1;...;a1])
an-1
[an-2;...;a1])
...)
a2
[a1])
a1
[]] *)letfold_right_and_leftflhd=letrecauxtl=function|[]->hd|a::l->lethd=aux(a::tl)linfhdatlinaux[]l(* Match sets as lists according to a matching function, also folding a side effect *)letrecfold_left2_setefxl1l2=matchl1with|a1::l1->letrecfindseen=function|[]->raisee|a2::l2->tryfold_left2_setef(fxa1a2l1l2)l1(List.rev_appendseenl2)withe'whene'=e->find(a2::seen)l2infind[]l2|[]->ifl2=[]thenxelseraisee(* Poor man's monadic map *)letrecfold_left_mapfe=function|[]->(e,[])|h::t->lete',h'=fehinlete'',t'=fold_left_mapfe'tine'',h'::t'(* (* tail-recursive version of the above function *)
let fold_left_map f e l =
let g (e,b') h =
let (e',h') = f e h in
(e',h'::b')
in
let (e',lrev) = List.fold_left g (e,[]) l in
(e',List.rev lrev)
*)(* The same, based on fold_right, with the effect accumulated on the right *)letfold_right_mapfle=List.fold_right(funx(l,e)->let(y,e)=fxein(y::l,e))l([],e)leton_sndf(x,y)=(x,fy)letfold_left2_mapfell'=on_sndList.rev@@List.fold_left2(fun(e,l)xx'->let(e,y)=fexx'in(e,y::l))(e,[])ll'letfold_right2_mapfll'e=List.fold_right2(funxx'(l,e)->let(y,e)=fxx'ein(y::l,e))ll'([],e)letfold_left3_mapfell'l''=on_sndList.rev@@fold_left3(fun(e,l)xx'x''->let(e,y)=fexx'x''in(e,y::l))(e,[])ll'l''letfold_left4_mapfel1l2l3l4=on_sndList.rev@@fold_left4(fun(e,l)x1x2x3x4->let(e,y)=fex1x2x3x4in(e,y::l))(e,[])l1l2l3l4(** {6 Splitting} *)letexceptcmpxl=List.filter(funy->not(cmpxy))lletremove=except(* Alias *)letrecremove_firstp=function|b::lwhenpb->l|b::l->b::remove_firstpl|[]->raiseNot_foundletextract_firstpli=letreclooprev_left=function|[]->raiseNot_found|x::right->ifpxthenList.rev_appendrev_leftright,xelseloop(x::rev_left)rightinloop[]liletinsertpvl=letrecinsrec=function|[]->[v]|h::tl->ifpvhthenv::h::tlelseh::insrectlininsreclletrecfind_mapf=function|[]->raiseNot_found|x::l->matchfxwith|None->find_mapfl|Somey->y(* FIXME: again, generic hash function *)letsubsetl1l2=lett2=Hashtbl.create151inList.iter(funx->Hashtbl.addt2x())l2;letreclook=function|[]->true|x::ll->tryHashtbl.findt2x;lookllwithNot_found->falseinlookl1(** [goto i l] splits [l] into two lists [(l1,l2)] such that
[(List.rev l1)++l2=l] and [l1] has length [i]. It raises
[IndexOutOfRange] when [i] is negative or greater than the
length of [l]. *)exceptionIndexOutOfRangeletgotonl=letrecgotoiacc=function|tlwhenInt.equali0->(acc,tl)|h::t->goto(predi)(h::acc)t|[]->raiseIndexOutOfRangeingoton[]l(* [chop i l] splits [l] into two lists [(l1,l2)] such that
[l1++l2=l] and [l1] has length [i].
It raises [Failure] when [i] is negative or greater than the length of [l] *)letchopnl=trylet(h,t)=gotonlin(List.revh,t)withIndexOutOfRange->failwith"List.chop"(* spiwack: should raise [IndexOutOfRange] but I'm afraid of missing
a try/with when replacing the exception. *)(* [split_when p l] splits [l] into two lists [(l1,a::l2)] such that
[l1++(a::l2)=l], [p a=true] and [p b = false] for every element [b] of [l1].
If there is no such [a], then it returns [(l,[])] instead *)letsplit_whenp=letrecsplit_when_loopxy=matchywith|[]->(List.revx,[])|(a::l)->if(pa)then(List.revx,y)elsesplit_when_loop(a::x)linsplit_when_loop[]letfirstnnl=letrecauxaccnl=matchn,lwith|0,_->List.revacc|n,h::t->aux(h::acc)(predn)t|_->failwith"firstn"inaux[]nlletrecsep_last=function|[]->failwith"sep_last"|hd::[]->(hd,[])|hd::tl->let(l,tl)=sep_lasttlin(l,hd::tl)(* Drop the last element of a list *)letrecdrop_last=function|[]->failwith"drop_last"|hd::[]->[]|hd::tl->hd::drop_lasttlletreclast=function|[]->failwith"List.last"|hd::[]->hd|_::tl->lasttlletlastnnl=letlen=List.lengthlinletrecauxml=ifInt.equalmnthenlelseaux(m-1)(List.tll)iniflen<nthenfailwith"lastn"elseauxlenlletrecskipnnl=matchn,lwith|0,_->l|_,[]->failwith"List.skipn"|n,_::l->skipn(predn)lletskipn_at_leastnl=tryskipnnlwithFailure_whenn>=0->[](** if [l=p++t] then [drop_prefix p l] is [t] else [l] *)letdrop_prefixcmppl=letrecdrop_prefix_rec=function|(h1::tp,h2::tl)whencmph1h2->drop_prefix_rec(tp,tl)|([],tl)->tl|_->lindrop_prefix_rec(p,l)letshare_tailsl1l2=letrecshr_revacc=function|(x1::l1,x2::l2)whenx1==x2->shr_rev(x1::acc)(l1,l2)|(l1,l2)->(List.revl1,List.revl2,acc)inshr_rev[](List.revl1,List.revl2)(** {6 Association lists} *)letmap_assocf=map(fun(x,a)->(x,fa))letrecassoc_ffa=function|(x,e)::xs->iffaxtheneelseassoc_ffaxs|[]->raiseNot_foundletremove_assoc_ffal=tryremove_first(fun(x,_)->fax)lwithNot_found->lletmem_assoc_ffal=List.exists(fun(x,_)->fax)l(** {6 Operations on lists of tuples} *)letrecsplit_looppq=function|[]->()|(x,y)::l->letcl={head=x;tail=[]}inletcr={head=y;tail=[]}inp.tail<-castcl;q.tail<-castcr;split_loopclcrlletsplit=function|[]->[],[]|(x,y)::l->letcl={head=x;tail=[]}inletcr={head=y;tail=[]}insplit_loopclcrl;(castcl,castcr)letreccombine_looppl1l2=matchl1,l2with|[],[]->()|x::l1,y::l2->letc={head=(x,y);tail=[]}inp.tail<-castc;combine_loopcl1l2|_->invalid_arg"List.combine"letcombinel1l2=matchl1,l2with|[],[]->[]|x::l1,y::l2->letc={head=(x,y);tail=[]}incombine_loopcl1l2;castc|_->invalid_arg"List.combine"letrecsplit3_looppqr=function|[]->()|(x,y,z)::l->letcp={head=x;tail=[]}inletcq={head=y;tail=[]}inletcr={head=z;tail=[]}inp.tail<-castcp;q.tail<-castcq;r.tail<-castcr;split3_loopcpcqcrlletsplit3=function|[]->[],[],[]|(x,y,z)::l->letcp={head=x;tail=[]}inletcq={head=y;tail=[]}inletcr={head=z;tail=[]}insplit3_loopcpcqcrl;(castcp,castcq,castcr)(** XXX TODO tailrec *)letrecsplit4=function|[]->([],[],[],[])|(a,b,c,d)::l->let(ra,rb,rc,rd)=split4lin(a::ra,b::rb,c::rc,d::rd)letreccombine3_looppl1l2l3=matchl1,l2,l3with|[],[],[]->()|x::l1,y::l2,z::l3->letc={head=(x,y,z);tail=[]}inp.tail<-castc;combine3_loopcl1l2l3|_->invalid_arg"List.combine3"letcombine3l1l2l3=matchl1,l2,l3with|[],[],[]->[]|x::l1,y::l2,z::l3->letc={head=(x,y,z);tail=[]}incombine3_loopcl1l2l3;castc|_->invalid_arg"List.combine3"(** {6 Operations on lists seen as sets, preserving uniqueness of elements} *)(** Add an element, preserving uniqueness of elements *)letadd_setcmpxl=ifmem_fcmpxlthenlelsex::l(** List equality up to permutation (but considering multiple occurrences) *)leteq_setcmpl1l2=letrecauxl1=function|[]->is_emptyl1|a::l2->aux(remove_first(cmpa)l1)l2intryauxl1l2withNot_found->falseletrecmerge_setcmpl1l2=matchl1,l2with|[],l2->l2|l1,[]->l1|h1::t1,h2::t2->letc=cmph1h2inifInt.equalc0thenh1::merge_setcmpt1t2elseifc<=0thenh1::merge_setcmpt1l2elseh2::merge_setcmpl1t2letintersectcmpl1l2=filter(funx->mem_fcmpxl2)l1letunioncmpl1l2=letrecurec=function|[]->l2|a::l->ifmem_fcmpal2thenureclelsea::ureclinurecl1letsubtractcmpl1l2=ifis_emptyl2thenl1elseList.filter(funx->not(mem_fcmpxl2))l1letunionql1l2=union(==)l1l2letsubtractql1l2=subtract(==)l1l2(** {6 Uniqueness and duplication} *)(* FIXME: we should avoid relying on the generic hash function,
just as we'd better avoid Pervasives.compare *)letdistinctl=letvisited=Hashtbl.create23inletrecloop=function|h::t->ifHashtbl.memvisitedhthenfalseelsebeginHashtbl.addvisitedhh;looptend|[]->trueinlooplletdistinct_fcmpl=letrecloop=function|a::b::_whenInt.equal(cmpab)0->false|a::l->loopl|[]->trueinloop(List.sortcmpl)(* FIXME: again, generic hash function *)letuniquizel=letvisited=Hashtbl.create23inletrecauxaccchanged=function|h::t->ifHashtbl.memvisitedhthenauxacctruetelsebeginHashtbl.addvisitedhh;aux(h::acc)changedtend|[]->ifchangedthenList.revaccelselinaux[]falsel(** [sort_uniquize] might be an alternative to the hashtbl-based
[uniquize], when the order of the elements is irrelevant *)letrecuniquize_sortedcmp=function|a::b::lwhenInt.equal(cmpab)0->uniquize_sortedcmp(a::l)|a::l->a::uniquize_sortedcmpl|[]->[]letsort_uniquizecmpl=uniquize_sortedcmp(List.sortcmpl)letmincmpl=letrecauxcur=function|[]->cur|x::l->ifcmpxcur<0thenauxxlelseauxcurlinmatchlwith|x::l->auxxl|[]->raiseNot_foundletrecduplicatescmp=function|[]->[]|x::l->letl'=duplicatescmplinifmem_fcmpxlthenadd_setcmpxl'elsel'(** {6 Cartesian product} *)(* A generic cartesian product: for any operator (**),
[cartesian (**) [x1;x2] [y1;y2] = [x1**y1; x1**y2; x2**y1; x2**y1]],
and so on if there are more elements in the lists. *)letcartesianopl1l2=map_append(funx->map(opx)l2)l1(* [cartesians] is an n-ary cartesian product: it iterates
[cartesian] over a list of lists. *)letcartesiansopinitll=List.fold_right(cartesianop)ll[init](* combinations [[a;b];[c;d]] gives [[a;c];[a;d];[b;c];[b;d]] *)letcombinationsl=cartesians(funxl->x::l)[]l(* Keep only those products that do not return None *)letcartesian_filteropl1l2=map_append(funx->map_filter(opx)l2)l1(* Keep only those products that do not return None *)letcartesians_filteropinitll=List.fold_right(cartesian_filterop)ll[init](* Factorize lists of pairs according to the left argument *)letrecfactorize_leftcmp=function|(a,b)::l->letal,l'=partition(fun(a',_)->cmpaa')lin(a,(b::mapsndal))::factorize_leftcmpl'|[]->[]moduleSmart=structletrecmapfl=matchlwith|[]->l|h::tl->leth'=fhinlettl'=mapftlinifh'==h&&tl'==tlthenlelseh'::tl'endmoduletypeMonoS=sigtypeeltvalequal:eltlist->eltlist->boolvalmem:elt->eltlist->boolvalassoc:elt->(elt*'a)list->'avalmem_assoc:elt->(elt*'a)list->boolvalremove_assoc:elt->(elt*'a)list->(elt*'a)listvalmem_assoc_sym:elt->('a*elt)list->boolend