123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292moduleL=Stdlib.ListincludeLletzip=combineletunzip=splitopenBase(** [pp elt sep ppf l] prints the list [l] on the formatter [ppf] using
[sep] as separator, and [elt] for printing the elements. *)letpp:'app->unitoutfmt->'alistpp=funeltsep->Format.pp_print_list~pp_sep:(unitsep)elt(** Total order on lists. *)letcmp:'acmp->'alistcmp=funcmp_elt->letreccmpll'=matchl,l'with|[],[]->0|[],_::_->-1|_::_,[]->1|x::l,x'::l'->lexcmp_eltcmp(x,l)(x',l')incmp(** [eq eq_elt l1 l2] tests the equality of [l1] and [l2], comparing their
elements with [eq_elt]. *)leteq:'aeq->'alisteq=funeq_eltl1l2->tryL.for_all2eq_eltl1l2withInvalid_argument_->false(** [find_map f l] applies [f] to the elements of [l] in order, and returns
the first result of the form [Some v], or [None] if none exist.
@since 4.10.0 *)letrecfind_mapf=function|[]->None|x::l->beginmatchfxwith|Some_asresult->result|None->find_mapflend(** [filter_map f l] applies [f] to every element of [l], filters
out the [None] elements and returns the list of the arguments of
the [Some] elements.
@since 4.08.0 *)letfilter_map:('a->'boption)->'alist->'blist=funf->letrecauxaccu=function|[]->revaccu|x::l->matchfxwith|None->auxaccul|Somev->aux(v::accu)linaux[](** [concat_map f l] gives the same result as
{!concat}[ (]{!map}[ f l)]. Tail-recursive.
@since 4.10.0 *)letconcat_mapfl=letrecauxfacc=function|[]->revacc|x::l->letxs=fxinauxf(rev_appendxsacc)linauxf[]l(** [filter_rev_map f l] is equivalent to [filter_map f (List.rev l)], but it
only traverses the list once and is tail-recursive. *)letfilter_rev_map:('a->'boption)-> 'alist->'blist=funf->letrecauxacc=function|[]->acc|hd::tl->matchfhdwith|Somex->aux(x::acc)tl|None->auxacctlinaux[](** [filteri_map f l] applies [f] element wise on [l] and keeps [x] such that
for [e] in [l], [f e = Some(x)]. *)letfilteri_map:(int->'a->'boption)->'alist->'blist=funfl->letrecloopk=function|[]->[]|h::t->(matchfkhwith|Somex->x::loop(succk)t|None->loop(succk)t)inloop0l(** [cut l k] returns a pair of lists [(l1, l2)] such that [l1] has length
[min (List.length l) k] and [l1 @ l2] is equal to [l]. *)letcut:'alist->int->'alist*'alist=funlk->letreccutacclk=ifk<=0then(L.revacc,l)elsematchlwith|[]->(L.revacc,l)|x::l->cut(x::acc)l(k-1)inifk<=0then([],l)elsecut[]lklet_=assert(cut[1;2;3]0=([],[1;2;3]));assert(cut[1;2;3]1=([1],[2;3]));assert(cut[1;2;3]2=([1;2],[3]));assert(cut[1;2;3]3=([1;2;3],[]));assert(cut[1;2;3]4=([1;2;3],[]))(** [add_array a1 a2 l] returns a list containing the elements of [l], and the
(corresponding) elements of [a1] and [a2]. Note that [a1] and [a2] should
have the same lenght otherwise [Invalid_argument] is raised. *)letadd_array2:'aarray->'barray->('a*'b)list->('a*'b)list=funa1a2l->letres=reflinArray.iter2(funx1x2->res:=(x1,x2)::!res)a1a2;!res(** [same_length l1 l2] returns [true] whenever [l1] and [l2] are lists of the
same length. The function stops as soon as possible. *)letrecsame_length:'alist->'blist->bool=funl1l2->matchl1,l2with|[],[]->true|_::l1,_::l2->same_lengthl1l2|_->false(** [max ?cmp l] finds the max of list [l] with compare function [?cmp]
defaulting to [Stdlib.compare].
@raise Invalid_argument if [l] is empty. *)letmax:?cmp:('a->'a->int)->'alist->'a=fun?(cmp=Stdlib.compare)li->matchliwith|[]->invalid_arg"Extra.List.max"|h::t->letmaxe1e2=ifcmpe1e2>=0thene1elsee2inL.fold_leftmaxht(** [assoc_eq e k l] is [List.assoc k l] with equality function [e].
@raise Not_found if [k] is not a key of [l]. *)letassoc_eq:'aeq->'a->('a*'b)list->'b=funeqk->letrecloop=function|[]->raiseNot_found|(x,e)::_wheneqxk->e|_::t->looptinloop(** [remove_phys_dups l] uniqify list [l] keeping only the last element, using
physical equality. *)letrecremove_phys_dups:'alist->'alist=function|[]->[]|x::xs->letxs=remove_phys_dupsxsinifL.memqxxsthenxselsex::xs(** [destruct l i] returns a triple [(left_rev, e, right)] where [e] is the
[i]-th element of [l], [left_rev] is the reversed prefix of [l] up to its
[i]-th element (excluded), and [right] is the remaining suffix of [l]
(starting at its [i+1]-th element).
@raise Invalid_argument when [i < 0].
@raise Not_found when [i ≥ length v]. *)letdestruct:'alist->int->'alist*'a*'alist=letrecdestructlir=matchr,iwith|[],_->raiseNot_found|v::r,0->(l,v,r)|v::r,i->destruct(v::l)(i-1)rinfunei->ifi<0theninvalid_arg__LOC__;destruct[]ie(** [reconstruct left_rev l right] concatenates (reversed) [left_rev], [l] and
[right]. This function will typically be used in combination with
{!val:destruct} to insert a sublist [l] in the place of the element at
the specified position in the specified list. *)letreconstruct:'alist->'alist->'alist->'alist=funlmr->L.rev_appendl(m@r)(** [init n f] creates a list with [f 0] up to [f n] as its elements. Note
that [Invalid_argument] is raised if [n] is negative. *)letinit:int->(int->'a)->'alist=funnf->ifn<0theninvalid_arg"Extra.List.init";letrecloopk=ifk>nthen[]elsefk::loop(k+1)inloop0(** [mem_sorted cmp x l] tells whether [x] is in [l] assuming that [l] is
sorted wrt [cmp]. *)letmem_sorted:'acmp->'a->'alist->bool=funcmpx->letrecmem_sortedl=matchlwith|[]->false|y::l->matchcmpxywith0->true|nwhenn>0->mem_sortedl|_->falseinmem_sorted(** [insert cmp x l] inserts [x] in the list [l] assuming that [l] is sorted
in increasing order wrt [cmp]. *)letinsert:'acmp->'a->'alist->'alist=funcmpx->letrecinsertacc=function|y::l'whencmpxy>0->insert(y::acc)l'|l->L.rev_appendacc(x::l)ininsert[](* unit tests *)let_=assert(insertStdlib.compare0[1;2;3]=[0;1;2;3]&&insertStdlib.compare2[1;2;3]=[1;2;2;3]&&insertStdlib.compare4[1;2;3]=[1;2;3;4])(** [insert cmp x l] inserts [x] in the list [l] assuming that [l] is sorted
in increasing order wrt [cmp], but only if [x] does not occur in [l]. *)letinsert_uniq:'acmp->'a->'alist->'alist=funcmpx->letexceptionFoundinletrecinsertaccl=matchlwith|[]->L.rev_appendacc[x]|y::l'->beginletn=cmpxyinmatchnwith|0->raiseFound|_whenn>0->insert(y::acc)l'|_->L.rev_appendacc(x::l)endinfunl->tryinsert[]lwithFound->l(* unit tests *)let_=assert(letl=[2;4;6]ininsert_uniqStdlib.compare1l=[1;2;4;6]&&insert_uniqStdlib.compare3l=[2;3;4;6]&&insert_uniqStdlib.compare7l=[2;4;6;7]&&insert_uniqStdlib.compare4l==l)(** [split_last l] returns [(l',x)] if [l = append l' [x]], and
@raise Invalid_argument otherwise. *)letsplit_last:'alist->'alist*'a=funl->matchrevlwith|hd::tl->(revtl,hd)|[]->invalid_arg"split_last: empty list"(** [rev_mapi f [x1;..;xn]] returns [f (n-1) xn; ..; f 0 x1]. *)letrev_mapif=letrecauxaccil=matchlwith|[]->acc|x::l->aux(fix::acc)(i+1)linaux[]0(** [swap i xs] put the i-th element (counted from 0) of [xs] at the head.
@raise Invalid_argument if the i-th element does not exist. *)letswap:int->'alist->'alist=funixs->letrecswapaccixs=match(i,xs)with|(0,x::xs)->x::rev_appendaccxs|(i,x::xs)->swap(x::acc)(i-1)xs|(_,_)->invalid_arg(__LOC__^"swap")inswap[]ixs(** [fold_left_while f cond a [b1 b2 ..]] computes (f..(f (f a b1) b2)..bm)
where [cond] is true for b1..bm and false for b_m+1 or bm is last element *)letrecfold_left_whilefcondaccl=matchlwith|x::_whennot(condx)->acc|x::xs->fold_left_whilefcond(faccx)xs|[]->acc(** [remove_first f l] removes from [l] the first element satisfying [f]. *)letremove_first:('a->bool)->'alist->'alist=funf->letrecremacc=function|[]->revacc|x::l->iffxthenrev_appendacclelserem(x::acc)linrem[](** [remove_heads n xs] remove the min(n,length xs) elements of [xs]. *)letrecremove_headsn=function|_::xswhenn>0->remove_heads(n-1)xs|xs->xs(** [split f l] returns the tuple [(l1,x,l2)] such that [x] is the first
element of [l] satisying [f], [l1] is the sub-list of [l] preceding [x],
and [l2] is the sub-list of [l] following [x].
@raise Not_found if there is no element of [l] satisying [f]. *)letsplit:('a->bool)->'alist->'alist*'a*'alist=funf->letrecsplitacc=function|[]->raiseNot_found|x::m->iffxthen(L.revacc,x,m)elsesplit(x::acc)minsplit[](** [iter_head_tail f l] iterates [f] on all pairs (head, tail) of [l]. *)letreciter_head_tail:('a->'alist->unit)->'alist->unit=funfl->matchlwith|[]->()|h::t->fht;iter_head_tailft