123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437(*
* BatSet - Extended operations on sets
* Copyright (C) 1996 Xavier Leroy
* 2009 David Rajchenbach-Teller, LIFO, Universite d'Orleans
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version,
* with the special exception on linking described in file LICENSE.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*)##V>=5##modulePervasives=Stdlib(*$inject
##V>=5##module Pervasives = Stdlib
*)moduletypeOrderedType=BatInterfaces.OrderedType(** Input signature of the functor {!Set.Make}. *)moduleConcrete=structtype'aset=|Empty|Nodeof 'aset*'a*'aset *intlet empty=Emptyletis_empty=functionEmpty->true|_->falseletis_singleton =function|Node(Empty,_x,Empty,_h)->true|_->false(*$T is_singleton
is_singleton (of_list []) = false
is_singleton (of_list [1]) = true
is_singleton (of_list [1;2]) = false
*)(* Sets are represented by balanced binary trees (the heights of the
children differ by at most 2 *)letheight=function|Empty->0|Node(_,_,_,h)->h(* Creates a new node with left son l, value v and right son r.
We must have all elements of l < v < all elements of r.
l and r must be balanced and | height l - height r | <= 2.
Inline expansion of height for better speed. *)letcreatelvr=lethl=matchlwithEmpty->0|Node(_,_,_,h)->hinlethr=matchrwithEmpty->0|Node(_,_,_,h)->hinNode(l,v,r,(ifhl>=hrthenhl+1elsehr+1))(* Same as create, but performs one step of rebalancing if necessary.
Assumes l and r balanced and | height l - height r | <= 3.
Inline expansion of create for better speed in the most frequent case
where no rebalancing is required. *)letballvr=lethl=matchlwithEmpty->0|Node(_,_,_,h)->hinlethr=matchrwithEmpty->0|Node(_,_,_,h)->hinifhl>hr+2thenbeginmatchlwithEmpty->invalid_arg"Set.bal"|Node(ll,lv,lr,_)->ifheight ll>=height lrthencreate lllv(create lrvr)elsebeginmatchlrwithEmpty->invalid_arg"Set.bal"|Node(lrl,lrv,lrr,_)->create(create ll lvlrl)lrv(createlrrvr)endendelseifhr>hl+2thenbeginmatchrwithEmpty->invalid_arg"Set.bal"|Node(rl,rv,rr,_)->ifheight rr>=height rlthencreate(createlvrl)rvrrelsebeginmatchrlwithEmpty->invalid_arg"Set.bal"|Node(rll,rlv,rlr,_)->create(createlvrll)rlv(createrlr rvrr)endendelseNode(l,v,r,(ifhl>=hrthenhl+1elsehr+1))(* Smallest and greatest element of a set *)letrecmin_elt=functionEmpty->raiseNot_found|Node(Empty,v,_r,_)->v|Node(l,_v,_r,_)->min_eltlletrecmin_elt_opt =functionEmpty->None|Node(Empty,v,_r,_)->Somev|Node(l,_v,_r,_)->min_elt_optlletget_root=function|Empty->raiseNot_found|Node(_l,v,_r,_)->vletpop_mins=letmini =ref(get_roots)inletrecloop=functionEmpty->raiseNot_found|Node(Empty,v,r,_)->mini:=v;r|Node(l,v,r,_)->bal(loopl)vrinlet others=loopsin(!mini,others)letpop_maxs=letmaxi =ref(get_roots)inletrecloop=functionEmpty->raiseNot_found|Node(l,v,Empty,_)->maxi:=v;l|Node(l,v,r,_)->ballv(loopr)inlet others=loopsin(!maxi,others)letrecmax_elt=functionEmpty->raiseNot_found|Node(_l,v,Empty,_)->v|Node(_l,_v,r,_)->max_eltrletrecmax_elt_opt =functionEmpty->None|Node(_l,v,Empty,_)->Somev|Node(_l,_v,r,_)->max_elt_optr(* Remove the smallest element of the given set *)letrecremove_min_elt =functionEmpty->invalid_arg"Set.remove_min_elt"|Node(Empty,_v,r,_)->r|Node(l,v,r,_)->bal(remove_min_eltl)vr(* Merge two trees l and r into one.
All elements of l must precede the elements of r.
Assume | height l - height r | <= 2. *)letmerget1t2=match(t1,t2)with(Empty,t)->t|(t,Empty)->t|(_,_)-> balt1(min_eltt2)(remove_min_eltt2)letpops=matchswith|Empty->raiseNot_found|Node(l,v,r,_)->v,mergelr(* Insertion of one element *)letrecaddcmpx=function|Empty->Node(Empty,x,Empty,1)|Node(l,v,r,_)ast->letc=cmpxvinifc=0thentelseifc<0thenletnl=addcmpxlinifnl==lthentelsebalnlvrelseletnr=addcmpxrinifnr==rthentelseballvnrletrecremove cmpx=function|Emptyast->t|Node(l,v,r,_)ast->letc=cmpxvinifc=0thenmergelrelseifc<0thenletnl=removecmpxlinifnl==lthentelsebalnlvrelseletnr=removecmpxrinifnr==rthentelseballvnr(* A variant of [remove] that throws [Not_found] on failure *)letrecremove_exn cmpx=function|Empty->raiseNot_found|Node(l,v,r,_)->letc=cmpxvinifc=0thenmergelrelseifc<0thenbal(remove_exncmpxl)vrelseballv(remove_exncmpxr)letupdatecmpxys=ifcmpxy<>0thenaddcmpy(remove_exncmpxs)elseletrecloop=function|Empty->raiseNot_found|Node(l,v,r,h)ast->letc=cmpxvinifc=0thenifv==ythentelseNode(l,y,r,h)elseifc<0thenletnl=looplinifnl==lthentelseNode(nl,v,r,h)elseletnr=looprinifnr==rthentelseNode(l,v,nr,h)inloopsletrecmemcmpx=functionEmpty->false|Node(l,v,r,_)->letc=cmpxvinc=0||memcmpx(ifc<0thenlelser)letrecfindcmpx=functionEmpty->raiseNot_found|Node(l,v,r,_)->letc=cmpxvinifc=0thenvelsefindcmpx(ifc<0thenlelser)letrecfind_optcmpx=functionEmpty->None|Node(l,v,r,_)->letc=cmpxvinifc=0thenSomevelsefind_optcmpx(ifc<0thenlelser)letrecfind_first_helper_found k0f=function|Empty->k0|Node(l,k,r,_)->iffkthenfind_first_helper_foundkflelsefind_first_helper_foundk0frletrecfind_first fm=matchmwith|Empty->raiseNot_found|Node(l,k,r,_)->iffkthenfind_first_helper_foundkflelsefind_firstfrletrecfind_first_opt fm=matchmwith|Empty->None|Node(l,k,r,_)->iffkthenSome(find_first_helper_foundkfl)elsefind_first_optfrletrecfind_last_helper_found k0f=function|Empty->k0|Node(l,k,r,_)->iffkthenfind_last_helper_foundkfrelsefind_last_helper_foundk0flletrecfind_last fm=matchmwith|Empty->raiseNot_found|Node(l,k,r,_)->iffkthenfind_last_helper_foundkfrelsefind_lastflletrecfind_last_opt fm=matchmwith|Empty->None|Node(l,k,r,_)->iffkthenSome(find_last_helper_foundkfr)elsefind_last_optflletreciterf=functionEmpty->()|Node(l,v,r,_)->iterfl;fv;iterfrletrecfoldfsaccu=matchswithEmpty->accu|Node(l,v,r,_)->foldfr(fv(foldflaccu))exceptionFoundletat_rank_exn is=ifi<0theninvalid_arg "Set.at_rank_exn: negative index not allowed";letres=ref(get_roots)in(* raises Not_found if empty *)trylet(_:int)=fold(funnodej->ifj<>ithenj+1elsebeginres:=node;raiseFoundend)s0ininvalid_arg"Set.at_rank_exn i s: i >= (Set.cardinal s)"withFound->!resletrecop_mapf=function|Empty->Empty|Node(l,x,r,h)->Node(op_mapfl,fx,op_mapfr,h)letsingleton x=Node(Empty,x,Empty,1)letrecadd_minv=function|Empty->singletonv|Node(l,x,r,_h)->bal(add_minvl)xrletrecadd_maxv=function|Empty->singletonv|Node(l,x,r,_h)->ballx(add_maxvr)(* Same as create and bal, but no assumptions are made on the
relative heights of l and r. *)letrecjoinlvr=match(l,r)with(Empty,_)->add_minvr|(_,Empty)->add_maxvl|(Node(ll,lv,lr,lh),Node(rl,rv,rr,rh))->iflh>rh+2thenbal lllv(joinlrvr)elseifrh>lh+2thenbal(joinlvrl)rvrrelsecreatelvr(* Splitting. split x s returns a triple (l, present, r) where
- l is the set of elements of s that are < x
- r is the set of elements of s that are > x
- present is false if s contains no element equal to x,
or true if s contains an element equal to x. *)letrec split cmpx=functionEmpty->(Empty,false,Empty)|Node(l,v,r,_)->letc=cmpxvinifc=0then(l,true,r)elseifc<0thenlet(ll,pres,rl)=splitcmpxlin(ll,pres,joinrlvr)elselet(lr,pres,rr)=splitcmpxrin(joinlvlr,pres,rr)(* split_opt x s returns a triple (l, maybe_v, r) where
- l is the set of elements of s that are < x
- r is the set of elements of s that are > x
- maybe_v is None if s contains no element equal to x,
or (Some v) if s contains an element v that compares equal to x. *)letrecsplit_opt cmpx=function|Empty->(Empty,None,Empty)|Node(l,v,r,_)->letc=cmpxvinifc=0then(l,Somev,r)elseifc<0thenlet(ll,pres,rl)=split_optcmpxlin(ll,pres,joinrlvr)else(* c > 0 *)let(lr,pres,rr)=split_optcmpxrin(joinlvlr,pres,rr)(*$inject
let s12 = of_list [1; 2 ] ;;
let s45 = of_list [ 4; 5] ;;
let s1245 = of_list [1; 2; 4; 5] ;;
let s12345 = of_list [1; 2; 3; 4; 5] ;;
*)(*$T split_opt
let l1, mv1, r1 = split_opt 3 s1245 in \
(elements l1, mv1, elements r1) = ([1; 2], None , [4; 5])
let l2, mv2, r2 = split_opt 3 s12345 in \
(elements l2, mv2, elements r2) = ([1; 2], Some 3, [4; 5])
*)(* returns a pair of sets: ({y | y < x}, {y | y >= x}) *)letsplit_ltcmpxs=letl,maybe,r=split_optcmpxsinmatch maybewith|None->l,r|Some eq_x->l,addcmpeq_xr(*$T split_lt
let l, r = split_lt 3 s12345 in \
(elements l, elements r) = ([1; 2], [3; 4; 5])
let l, r = split_lt 3 s12 in \
(elements l, elements r) = ([1; 2], [])
let l, r = split_lt 3 s45 in \
(elements l, elements r) = ([], [4; 5])
*)(* returns a pair of sets: ({y | y <= x}, {y | y > x}) *)letsplit_lecmpxs=letl,maybe,r=split_optcmpxsinmatch maybewith|None->l,r|Some eq_x->addcmpeq_xl,r(*$T split_le
let l, r = split_le 3 s12345 in \
(elements l, elements r) = ([1; 2; 3], [4; 5])
let l, r = split_le 3 s12 in \
(elements l, elements r) = ([1; 2], [])
let l, r = split_le 3 s45 in \
(elements l, elements r) = ([], [4; 5])
*)type'aiter=E|Cof'a*'aset*'aiterletreccardinal=functionEmpty->0|Node(l,_v,r,_)->cardinall+1+cardinalrletrecelements_aux accu=functionEmpty->accu|Node(l,v,r,_)->elements_aux(v::elements_auxaccur)lletelementss=elements_aux[]sletto_list=elementsletto_arrays=matchswith|Empty->[||]|Node(_,e,_,_)->letarr=Array.make(cardinals)einleti=ref0initer(funx->Array.unsafe_setarr(!i)x;incri)s;arrletreccons_iter st=matchswithEmpty->t|Node(l,e,r,_)->cons_iterl(C(e,r,t))letrecrev_cons_iter st=matchswithEmpty->t|Node(l,e,r,_)->rev_cons_iterr(C(e,l,t))letreccons_iter_fromcmpk2me=matchmwith|Empty->e|Node(l,k,r,_)->ifcmpk2k<=0thencons_iter_fromcmpk2l(C(k,r,e))elsecons_iter_fromcmpk2reletenum_next l()=match!lwithE->raiseBatEnum.No_more_elements|C(e,s,t)->l:=cons_iterst;eletenum_backwards_next l()=match!lwithE->raiseBatEnum.No_more_elements|C(e,s,t)->l:=rev_cons_iterst;eletenum_count l()=letrecauxn=functionE->n|C(_e,s,t)->aux(n+1+cardinals)tinaux0!lletenumt=letrecmakel=letl=reflinlet clone()=make!linBatEnum.make~next:(enum_nextl)~count:(enum_countl)~cloneinmake(cons_itertE)letbackwards t=letrecmakel=letl=reflinlet clone()=make!linBatEnum.make~next:(enum_backwards_nextl)~count:(enum_countl)~cloneinmake(rev_cons_itertE)letof_enumcmpe=BatEnum.fold(funaccelem->addcmpelemacc)emptyeletof_listcmpl=List.fold_left(funax->addcmpxa)emptylletof_arraycmpl=Array.fold_left(funax->addcmpxa)emptyllet print?(first="{")?(last="}")?(sep=",")print_eltoutt=BatEnum.print ~first~last ~sep(funoute->BatPrintf.fprintfout"%a"print_elte)out(enumt)let choose=min_elt(* I'd rather this chose the root, but okay *)(*$= choose
42 (empty |> add 42 |> choose)
(empty |> add 0 |> add 1 |> choose) (empty |> add 1 |> add 0 |> choose)
*)letchoose_opt =min_elt_optletany=get_root(*$T any
empty |> add 42 |> any = 42
try empty |> any |> ignore ; false with Not_found -> true
*)letrecfor_allp=functionEmpty->true|Node(l,v,r,_)-> pv&&for_allpl&&for_allprletrecexistsp=functionEmpty->false|Node(l,v,r,_)-> pv||existspl||existsprletpartitioncmpps=letrecpart(t,fasaccu)=function|Empty->accu|Node(l,v,r,_)->part (part(ifpvthen(addcmpvt,f)else(t,addcmpvf))l)rinpart(Empty,Empty)sletconcat t1t2=match(t1,t2)with(Empty,t)->t|(t,Empty)->t|(_,_)->joint1(min_eltt2)(remove_min_eltt2)letreccartesian_product ab=matchawith|Empty->Empty|Node(la,xa,ra,_)->letlab=cartesian_productlabinletxab=op_map(funxb ->(xa,xb))binletrab=cartesian_productrabinconcat lab(concatxabrab)letrec union cmp12s1s2=match(s1,s2)with(Empty,t2)->t2|(t1,Empty)->t1|(Node(l1,v1,r1,h1),Node(l2,v2,r2,h2))->ifh1>=h2thenifh2=1thenaddcmp12v2s1elsebeginlet(l2,_,r2)=split cmp12v1s2injoin(union cmp12l1 l2)v1(union cmp12r1r2)endelseifh1=1thenaddcmp12v1s2elsebeginlet(l1,_,r1)=split cmp12v2s1injoin(union cmp12l1 l2)v2(union cmp12r1r2)endletrecfilterp=functionEmpty->Empty|(Node(l,v,r,_))ast->(* call [p] in the expected left-to-right order *)letl'=filterplinletpv=pvinletr'=filterprinifpvthenifl==l'&&r==r'thentelsejoinl'vr'elseconcat l'r'lettry_joincmplvr=(* [join l v r] can only be called when (elements of l < v <
elements of r); use [try_join l v r] when this property may
not hold, but you hope it does hold in the common case *)if(l=Empty||cmp(max_eltl)v<0)&&(r=Empty||cmpv(min_eltr)<0)thenjoinlvrelseunioncmpl(addcmpvr)letrecmap_endocmpf=function|Empty->Empty|Node(l,v,r,_)ast->(* enforce left-to-right evaluation order *)letl'=map_endocmpflinletv'=fvinletr'=map_endocmpfrinifl==l'&&v==v'&&r==r'thentelsetry_joincmp l'v'r'letrecmapcmpf=function|Empty->Empty|Node(l,v,r,_)->(* enforce left-to-right evaluation order *)letl'=mapcmpflinletv'=fvinletr'=mapcmpfrintry_joincmp l'v'r'lettry_concatcmp t1t2=match(t1,t2)with(Empty,t)->t|(t,Empty)->t|(_,_)->try_joincmpt1(min_eltt2)(remove_min_eltt2)letrecfilter_map_endo cmpf=function|Empty->Empty|Node(l,v,r,_)ast->(* enforce left-to-right evaluation order *)letl'=filter_map_endocmpflinletv'=fvinletr'=filter_map_endocmpfrinbeginmatchv'with|Somev'->ifl==l'&&v==v'&&r==r'thentelsetry_joincmp l'v'r'|None->try_concatcmp l'r'endletrecfilter_map cmpf=function|Empty->Empty|Node(l,v,r,_)->(* enforce left-to-right evaluation order *)letl'=filter_mapcmpflinletv'=fvinletr'=filter_mapcmpfrinbeginmatchv'with|Somev'->try_joincmp l'v'r'|None->try_concatcmp l'r'endletrecsym_diffcmp12s1s2=match(s1,s2)with(Empty,t2)->t2|(t1,Empty)->t1|(Node(l1,v1,r1,_),t2)->matchsplitcmp12v1t2with(l2,false,r2)->join(sym_diffcmp12l1 l2)v1(sym_diffcmp12r1r2)|(l2,true,r2)->concat(sym_diffcmp12l1l2)(sym_diffcmp12r1r2)letrec inter cmp12s1s2=match(s1,s2)with(Empty,_t2)->Empty|(_t1,Empty)->Empty|(Node(l1,v1,r1,_),t2)->matchsplitcmp12v1t2with(l2,false,r2)->concat(inter cmp12l1l2)(inter cmp12r1r2)|(l2,true,r2)->join(inter cmp12l1 l2)v1(inter cmp12r1r2)letrecdiffcmp12s1s2=match(s1,s2)with(Empty,_t2)->Empty|(t1,Empty)->t1|(Node(l1,v1,r1,_),t2)->matchsplitcmp12v1t2with(l2,false,r2)->join(diffcmp12l1 l2)v1(diffcmp12r1r2)|(l2,true,r2)->concat(diffcmp12l1l2)(diff cmp12r1r2)letrecdisjointcmp12s1s2=match(s1,s2)with(Empty,_)|(_,Empty)->true|(Node(l1,v1,r1,_),t2)->matchsplitcmp12v1t2with(l2,false,r2)->disjointcmp12l1l2&&disjointcmp12r1r2|(_l2,true,_r2)->falseletcomparecmp s1s2=letreccompare_auxt1't2'=match (t1',t2')withE,E->0|E,_->-1|_,E->1|C(e1,r1,t1),C(e2,r2,t2)->letc=cmp e1e2inifc=0thencompare_aux (cons_iterr1t1)(cons_iterr2t2)elsecincompare_aux (cons_iters1E)(cons_iters2E)let equalcmp s1s2=comparecmps1s2=0letrecsubsetcmp s1s2=match(s1,s2)withEmpty,_->true|_,Empty->false|Node(l1,v1,r1,_),(Node(l2,v2,r2,_)ast2)->letc=cmp v1v2inifc=0thensubsetcmp l1l2&&subsetcmp r1r2elseifc<0thensubset cmp(Node(l1,v1,Empty,0))l2&&subsetcmp r1t2elsesubset cmp(Node(Empty,v1,r1,0))r2&&subsetcmp l1t2letadd_seqcmpsm=BatSeq.fold_left(funme->addcmpem)msletof_seq cmps=add_seqcmpsemptyletrecseq_of_iter m()=matchmwith|E->BatSeq.Nil|C(k,r,e)->BatSeq.Cons(k,seq_of_iter(cons_iterre))letto_seqm=seq_of_iter(cons_itermE)letrecrev_seq_of_iter m()=matchmwith|E->BatSeq.Nil|C(k,r,e)->BatSeq.Cons(k,rev_seq_of_iter(rev_cons_iterre))letto_rev_seq m=rev_seq_of_iter(rev_cons_itermE)letto_seq_fromcmpkm=seq_of_iter(cons_iter_fromcmpkmE)endmoduletypeS=sigtypeelttypetvalempty:tvalis_empty:t->boolvalis_singleton:t->boolvalsingleton:elt->tvalmem:elt->t->boolvalfind:elt->t->eltvalfind_opt:elt->t->elt optionvalfind_first:(elt->bool)->t->eltvalfind_first_opt:(elt->bool)->t->elt optionvalfind_last:(elt->bool)->t->eltvalfind_last_opt:(elt->bool)->t->elt optionvaladd:elt->t->tvalremove:elt-> t->tvalremove_exn:elt-> t->tvalupdate:elt ->elt-> t->tvalunion:t-> t->tvalinter:t-> t->tvaldiff:t-> t->tvalsym_diff:t-> t->tvalcompare:t->t->intvalequal:t->t->boolvalsubset:t->t->boolvaldisjoint:t->t->boolvalcompare_subset:t->t->intvaliter:(elt->unit)->t->unitvalat_rank_exn:int->t->eltvalmap:(elt ->elt)->t->tvalfilter:(elt->bool)-> t->tvalfilter_map:(elt ->elt option)-> t->tvalfold:(elt->'a->'a)->t->'a->'avalfor_all:(elt->bool)->t->boolvalexists:(elt->bool)->t->boolvalpartition:(elt->bool)->t->t*tvalsplit:elt->t->t*bool*tvalsplit_opt:elt->t->t*elt option*tvalsplit_lt:elt->t->t*tvalsplit_le:elt->t->t*tvalcardinal:t->intvalelements:t->eltlistvalto_list:t->eltlistvalto_array:t->elt arrayvalmin_elt:t->eltvalmin_elt_opt:t->eltoptionvalpop_min:t->elt*tvalpop_max:t->elt*tvalmax_elt:t->eltvalmax_elt_opt:t->eltoptionvalchoose:t->eltvalchoose_opt:t->eltoptionvalany:t->eltvalpop:t->elt*tvalenum:t->eltBatEnum.tvalbackwards:t->eltBatEnum.tvalof_enum:eltBatEnum.t->tvalof_list:eltlist->tvalof_array:eltarray->tvalto_seq:t->eltBatSeq.tvalto_rev_seq:t->eltBatSeq.tvalto_seq_from:elt->t->eltBatSeq.tvaladd_seq:eltBatSeq.t->t->tvalof_seq:eltBatSeq.t->tvalprint:?first:string->?last:string->?sep:string->('aBatInnerIO.output->elt->unit)->'aBatInnerIO.output->t->unit(** Operations on {!Set} without exceptions.*)moduleExceptionless:sigvalmin_elt:t->elt optionvalmax_elt:t->eltoptionvalchoose:t->elt optionvalany:t->elt optionvalfind:elt->t->elt optionend(** Operations on {!Set} with labels. *)moduleLabels:sigvaliter:f:(elt->unit)->t->unitvalfold:f:(elt->'a->'a)->t->init:'a->'avalfor_all:f:(elt->bool)->t->boolvalexists:f:(elt->bool)->t->boolvalmap:f:(elt ->elt)->t->tvalfilter:f:(elt->bool)->t->tvalfilter_map:f:(elt ->elt option)->t->tvalpartition:f:(elt->bool)->t->t*tendend(** Output signature of the functor {!Set.Make}. *)moduleMake(Ord:OrderedType)=structincludeSet.Make(Ord)(*Breaking the abstraction*)typeimplementation=eltConcrete.setexternalimpl_of_t:t->implementation ="%identity"externalt_of_impl:implementation->t="%identity"letcardinalt=Concrete.cardinal(impl_of_tt)letis_singleton t=Concrete.is_singleton(impl_of_tt)letenumt=Concrete.enum(impl_of_tt)letof_enume=t_of_impl(Concrete.of_enumOrd.comparee)letbackwards t=Concrete.backwards(impl_of_tt)letremoveet=t_of_impl(Concrete.removeOrd.comparee(impl_of_tt))letremove_exn et=t_of_impl(Concrete.remove_exnOrd.comparee(impl_of_tt))letupdatee1e2t=t_of_impl(Concrete.updateOrd.comparee1e2(impl_of_tt))letaddet=t_of_impl(Concrete.addOrd.comparee(impl_of_tt))letiterft=Concrete.iterf(impl_of_tt)letat_rank_exn it=Concrete.at_rank_exni(impl_of_tt)letmapft=t_of_impl(Concrete.map_endoOrd.comparef(impl_of_tt))letfoldftacc=Concrete.foldf(impl_of_tt)accletfilterft=t_of_impl(Concrete.filterf(impl_of_tt))letfilter_map ft=t_of_impl(Concrete.filter_map_endoOrd.comparef(impl_of_tt))letfindxt=Concrete.findOrd.comparex(impl_of_tt)letfind_optxt=Concrete.find_optOrd.comparex(impl_of_tt)letfind_first ft=Concrete.find_firstf(impl_of_tt)letfind_first_opt ft=Concrete.find_first_optf(impl_of_tt)letfind_last ft=Concrete.find_lastf(impl_of_tt)letfind_last_opt ft=Concrete.find_last_optf(impl_of_tt)letexistsft=Concrete.existsf(impl_of_tt)letfor_allft=Concrete.for_allf(impl_of_tt)letpartition ft=letl,r=Concrete.partitionOrd.comparef(impl_of_tt)in(t_of_impll,t_of_implr)letmin_eltt=Concrete.min_elt(impl_of_tt)letmin_elt_opt t=Concrete.min_elt_opt(impl_of_tt)letpop_mint=letmini,others=Concrete.pop_min(impl_of_tt)in(mini,t_of_implothers)letpop_maxt=letmaxi,others=Concrete.pop_max(impl_of_tt)in(maxi,t_of_implothers)letmax_eltt=Concrete.max_elt(impl_of_tt)letmax_elt_opt t=Concrete.max_elt_opt(impl_of_tt)letchooset=Concrete.choose(impl_of_tt)letchoose_opt t=Concrete.choose_opt(impl_of_tt)letanyt=Concrete.any(impl_of_tt)letpopt=lete,t=Concrete.pop(impl_of_tt)ine,t_of_impltletsplites=letl,v,r=Concrete.splitOrd.comparee(impl_of_ts)in(t_of_impll,v,t_of_implr)letsplit_opt es=letl,maybe_v,r=Concrete.split_optOrd.comparee(impl_of_ts)in(t_of_impll,maybe_v,t_of_implr)letsplit_ltes=letl,r=Concrete.split_ltOrd.comparee(impl_of_ts)in(t_of_impll,t_of_implr)letsplit_lees=letl,r=Concrete.split_leOrd.comparee(impl_of_ts)in(t_of_impll,t_of_implr)letsingleton e=t_of_impl(Concrete.singletone)letelementst=Concrete.elements(impl_of_tt)letto_list=elementsletto_arrayt=Concrete.to_array(impl_of_tt)let unions1s2=t_of_impl(Concrete.unionOrd.compare(impl_of_ts1)(impl_of_ts2))letdiffs1s2=t_of_impl(Concrete.diffOrd.compare(impl_of_ts1)(impl_of_ts2))let inters1s2=t_of_impl(Concrete.interOrd.compare(impl_of_ts1)(impl_of_ts2))letsym_diffs1s2=t_of_impl(Concrete.sym_diffOrd.compare(impl_of_ts1)(impl_of_ts2))letcomparet1t2=Concrete.compareOrd.compare(impl_of_tt1)(impl_of_tt2)let equalt1t2=Concrete.equalOrd.compare(impl_of_tt1)(impl_of_tt2)letsubset t1t2=Concrete.subsetOrd.compare(impl_of_tt1)(impl_of_tt2)letdisjointt1t2=Concrete.disjointOrd.compare(impl_of_tt1)(impl_of_tt2)letadd_seqst=t_of_impl(Concrete.add_seqOrd.compares(impl_of_tt))letof_seqs=t_of_impl(Concrete.of_seqOrd.compares)letto_seqt=Concrete.to_seq(impl_of_tt)letto_rev_seq t=Concrete.to_rev_seq(impl_of_tt)letto_seq_from kt=Concrete.to_seq_fromOrd.comparek(impl_of_tt)letreccompare_subset s1s2=match (s1,impl_of_ts2)with(Concrete.Empty,Concrete.Empty)->0|(Concrete.Empty,_t2)->-1|(_t1,Concrete.Empty)->1|(Concrete.Node(l1,v1,r1,_),t2)->matchsplitv1(t_of_implt2)with(l2,true,r2)->(* v1 in both s1 and s2 *)(matchcompare_subsetl1l2,compare_subsetr1r2with|-1,-1|-1,0|0,-1->-1|0,0->0|1,1|1,0|0,1->1|_->min_int)|(l2,false,r2)->(* v1 in s1, but not in s2 *)if(compare_subsetl1 l2)>=0&&(compare_subsetr1 r2)>=0then1elsemin_intletcompare_subset s1s2=compare_subset(impl_of_ts1)s2letof_listl=t_of_impl(Concrete.of_listOrd.comparel)letof_arraya=t_of_impl(Concrete.of_arrayOrd.comparea)letprint ?first?last ?sepprint_elt outt=Concrete.print ?first?last ?sepprint_elt out(impl_of_tt)moduleExceptionless=structletmin_eltt=trySome(min_eltt)withNot_found->Noneletmax_eltt=trySome(max_eltt)withNot_found->Nonelet chooset=trySome(chooset)withNot_found->Noneletanyt=trySome(anyt)withNot_found->Noneletfindet=trySome(findet)withNot_found->NoneendmoduleLabels=structletiter~ft=iterftletfold~ft~init=foldftinitletfor_all~ft=for_allftlet exists~ft=existsftletmap~ft=mapftlet filter~ft=filterftletfilter_map ~ft=filter_mapftletpartition ~ft=partitionftendendmoduleInt=Make(BatInt)moduleInt32=Make(BatInt32)moduleInt64=Make(BatInt64)moduleNativeint=Make(BatNativeint)moduleFloat=Make(BatFloat)moduleChar=Make(BatChar)moduleString=Make(BatString)moduleMake2(O1:OrderedType)(O2:OrderedType)=structmoduleSet1=Make(O1)moduleSet2=Make(O2)moduleProduct=Make(structtypet=O1.t*O2.tletcompare(x1,y1)(x2,y2)=letc=O1.comparex1x2inifc=0thenO2.comparey1y2elsecend)letcartesian_product set1 set2=letp=Concrete.cartesian_product(Set1.impl_of_tset1)(Set2.impl_of_tset2)inProduct.t_of_impl pend(*$T
let module S1 = Make(BatInt) in \
let module S2 = Make(BatString) in \
let module P = Make2(BatInt)(BatString) in \
P.cartesian_product \
(List.fold_right S1.add [1;2;3] S1.empty) \
(List.fold_right S2.add ["a";"b"] S2.empty) \
|> P.Product.to_list = [1, "a"; 1, "b"; 2, "a"; 2, "b"; 3, "a"; 3, "b"]
*)modulePSet=struct(*$< PSet *)type'at={cmp:'a->'a->int;set:'aConcrete.set;}type'aenumerable ='attype'amappable ='atlet empty={cmp=compare;set=Concrete.empty}letcreate cmp={cmp =cmp;set=Concrete.empty}letget_cmp{cmp;_}=cmp(*$T get_cmp
get_cmp (create BatInt.compare) == BatInt.compare
*)letsingleton ?(cmp=compare)x={cmp =cmp;set=Concrete.singletonx}letis_emptys=Concrete.is_emptys.setletis_singletons=Concrete.is_singletons.setletmemxs=Concrete.mems.cmpxs.setletfindxs=Concrete.finds.cmpxs.setletfind_optxs=Concrete.find_opts.cmpxs.setletfind_firstfs=Concrete.find_firstfs.setletfind_first_optfs=Concrete.find_first_optfs.setletfind_lastfs=Concrete.find_lastfs.setletfind_last_optfs=Concrete.find_last_optfs.setletaddxs=let newset=Concrete.adds.cmpxs.setinifnewset ==s.setthenselse{swithset=newset}letremovexs=let newset=Concrete.removes.cmpxs.setinifnewset ==s.setthenselse{swithset=newset}letremove_exn xs={swithset=Concrete.remove_exns.cmpxs.set}letupdatexys=let newset=Concrete.updates.cmpxys.setinifnewset ==s.setthenselse{swithset=newset}letiterfs=Concrete.iterfs.setletat_rank_exnis=Concrete.at_rank_exnis.setletfoldfsacc=Concrete.foldfs.setaccletmapfs={cmp=Pervasives.compare;set=Concrete.mapPervasives.comparefs.set}letmap_endofs=let newset=Concrete.map_endoPervasives.comparefs.setinifs.set== newsetthenselse{cmp=s.cmp;set=newset}letfilterfs=let newset=Concrete.filterfs.setinifnewset ==s.setthenselse{swithset=newset}letfilter_map fs={cmp=compare;set=Concrete.filter_mapcomparefs.set}letfilter_map_endo fs=let newset=Concrete.filter_map_endocomparefs.setinifnewset ==s.setthenselse{cmp=s.cmp;set=newset}letexistsfs=Concrete.existsfs.setletcardinals=fold(fun _acc->acc+1)s0letelementss=Concrete.elementss.setletto_list=elementsletto_arrays=Concrete.to_arrays.setletchooses=Concrete.chooses.setletchoose_opts=Concrete.choose_opts.setletanys=Concrete.anys.setletmin_elts=Concrete.min_elts.setletmin_elt_opts=Concrete.min_elt_opts.setletpop_mins=letmini,others=Concrete.pop_mins.setin(mini,{swithset=others})letpop_maxs=letmaxi,others=Concrete.pop_maxs.setin(maxi,{swithset=others})letmax_elts=Concrete.max_elts.setletmax_elt_opts=Concrete.max_elt_opts.setletenums=Concrete.enums.setletof_enum?(cmp=compare)e={cmp;set=Concrete.of_enumcomparee}letof_enum_cmp ~cmpt={cmp =cmp;set=Concrete.of_enumcmpt}letof_list?(cmp=compare)l={cmp;set=Concrete.of_listcomparel}letof_array?(cmp=compare)a={cmp;set=Concrete.of_arraycomparea}letprint ?first?last ?sepprint_elt outs=Concrete.print ?first?last ?sepprint_elt outs.setletfor_allfs=Concrete.for_allfs.setletpartitionfs=letl,r=Concrete.partitions.cmpfs.setin{swithset=l},{swithset=r}letpops=let v,s'=Concrete.pops.setinv,{swithset=s'}letsplites=lets1,found,s2=Concrete.splits.cmpes.setin{swithset=s1},found,{swithset=s2}letsplit_opt es=lets1,maybe_v,s2=Concrete.split_opts.cmpes.setin{swithset=s1},maybe_v,{swithset=s2}letsplit_ltes=lets1,s2=Concrete.split_lts.cmpes.setin{swithset=s1},{swithset=s2}letsplit_lees=lets1,s2=Concrete.split_les.cmpes.setin{swithset=s1},{swithset=s2}let unions1s2={s1withset=Concrete.unions1.cmps1.sets2.set}letdiffs1s2={s1withset=Concrete.diffs1.cmps1.sets2.set}letsym_diffs1s2={s1withset=Concrete.sym_diffs1.cmps1.sets2.set}letintersect s1s2={s1withset=Concrete.inters1.cmps1.sets2.set}letcompares1s2=Concrete.compares1.cmps1.sets2.setletequals1s2=Concrete.equals1.cmps1.sets2.setletsubset s1s2=Concrete.subsets1.cmps1.sets2.setletdisjoints1s2=Concrete.disjoints1.cmps1.sets2.setletadd_seqst={twithset=Concrete.add_seqt.cmpst.set}let of_seq?(cmp=Pervasives.compare)s={set=Concrete.of_seq cmps;cmp =cmp}letto_seqt=Concrete.to_seqt.setletto_rev_seq t=Concrete.to_rev_seqt.setletto_seq_from kt=Concrete.to_seq_fromt.cmpkt.setend(*$>*)type'at='aConcrete.settype'aenumerable='attype'amappable ='atlet empty=Concrete.emptyletsingletonx=Concrete.singletonxletis_emptys=s=Concrete.Emptyletis_singletons=Concrete.is_singletonsletmemxs=Concrete.memPervasives.comparexsletfindxs=Concrete.findPervasives.comparexsletfind_optxs=Concrete.find_optPervasives.comparexsletfind_first fs=Concrete.find_firstfsletfind_last fs=Concrete.find_lastfsletfind_first_opt fs=Concrete.find_first_optfsletfind_last_opt fs=Concrete.find_last_optfs(*$T find
(find 1 (of_list [1;2;3;4;5;6;7;8])) == 1
(find 8 (of_list [1;2;3;4;5;6;7;8])) == 8
(find 1 (singleton 1)) == 1
let x = "abc" in (find "abc" (singleton x)) == x
let x = (1,1) in (find (1,1) (singleton x)) == x
let x,y = (1,1),(1,1) in find x (singleton y) == y
let x,y = [|0|],[|0|] in find x (singleton y) != x
try ignore (find (1,2) (singleton (1,1))); false with Not_found -> true
*)letaddxs=Concrete.addPervasives.comparexsletremovexs=Concrete.removePervasives.comparexsletremove_exn xs=Concrete.remove_exnPervasives.comparexsletupdatexys=Concrete.updatePervasives.comparexysletiterfs=Concrete.iterfsletat_rank_exn is=Concrete.at_rank_exnis(*$T
at_rank_exn 0 (of_list [1;2]) == 1
at_rank_exn 1 (of_list [1;2]) == 2
try ignore (at_rank_exn 0 empty); false with Not_found -> true
try ignore (at_rank_exn (-1) (singleton 1)); false \
with Invalid_argument _msg -> true
try ignore (at_rank_exn 1 (singleton 1)); false \
with Invalid_argument _msg -> true
*)letfoldfsacc=Concrete.foldfsaccletmapfs=Concrete.mapPervasives.comparefsletmap_endofs=Concrete.map_endoPervasives.comparefs(*$T map
map (fun _x -> 1) (of_list [1;2;3]) |> cardinal = 1
*)(*$T map_endo
let s = of_list [1;2;3] in s == (map_endo (fun x -> x) s)
let s = empty in s == (map_endo (fun x -> x+1) s)
*)letfilterfs=Concrete.filterfs(*$T filter
let s = of_list [1;2;3] in s == (filter (fun x -> x < 10) s)
let s = empty in s == (filter (fun x -> x > 10) s)
*)letfilter_mapfs=Concrete.filter_mapPervasives.comparefsletfilter_map_endo fs=Concrete.filter_map_endoPervasives.comparefs(*$T filter_map_endo
let s = of_list [1;2;3] in s == (filter_map_endo (fun x -> Some x) s)
let s = empty in s == (filter_map_endo (fun x -> Some x) s)
*)letexistsfs=Concrete.existsfsletcardinals=fold(fun _acc->acc+1)s0letelementss=Concrete.elementssletto_list=elementsletto_arrays=Concrete.to_arraysletchooses=Concrete.choosesletchoose_opts=Concrete.choose_opts(*$T choose_opt
choose_opt (of_list [1]) = Some 1
choose_opt (empty) = None
choose_opt (of_list []) = None
*)letanys=Concrete.anysletmin_elts=Concrete.min_eltsletmin_elt_opts=Concrete.min_elt_opts(*$Q min_elt
(Q.list Q.small_int) (fun l -> l = [] || \
let xs = List.map (fun i -> i mod 2, i) l in \
let s = ref (of_list xs) in \
let m = ref (min_elt !s) in \
while fst !m = 0 do \
s := remove !m !s; \
s := add (2,snd !m) !s; \
m := min_elt !s; \
done; \
for_all (fun (x,_) -> x <> 0) !s \
)
*)(*$T min_elt_opt
min_elt_opt (of_list [1;2;3]) = Some 1
min_elt_opt (empty) = None
min_elt_opt (of_list []) = None
*)letpop_mins=Concrete.pop_mins(*$T pop_min
try ignore (pop_min empty); false with Not_found -> true
pop_min (of_list [1;2]) = (1, singleton 2)
pop_min (singleton 2) = (2, empty)
pop_min (of_list [4;5;6;7]) = (4, of_list [5;6;7])
*)letpop_maxs=Concrete.pop_maxs(*$T pop_max
try ignore (pop_max empty); false with Not_found -> true
pop_max (of_list [1;2]) = (2, singleton 1)
pop_max (singleton 2) = (2, empty)
let maxi, others = pop_max (of_list [4;5;6;7]) in \
maxi = 7 && diff others (of_list [4;5;6]) = empty
*)letmax_elts=Concrete.max_eltsletmax_elt_opt s=Concrete.max_elt_opts(*$T max_elt_opt
max_elt_opt (of_list [1;2;3]) = Some 3
max_elt_opt (empty) = None
max_elt_opt (of_list []) = None
*)letenums=Concrete.enumsletof_enume=Concrete.of_enumPervasives.compareeletbackwards s=Concrete.backwardssletof_listl=Concrete.of_listPervasives.comparel(*$Q of_list
(Q.list Q.small_int) (fun l -> let xs = List.map (fun i -> i mod 5, i) l in \
let s1 = of_list xs |> enum |> List.of_enum in \
let s2 = List.sort_unique Legacy.compare xs in \
s1 = s2 \
)
*)letof_arraya=Concrete.of_arrayPervasives.comparealetprint ?first?last ?sepprint_elt outs=Concrete.print ?first?last ?sepprint_elt outsletfor_allfs=Concrete.for_allfsletpartition fs=Concrete.partitionPervasives.comparefsletpops=Concrete.popsletcartesian_product=Concrete.cartesian_productletsplites=Concrete.splitPervasives.compareesletsplit_opt es=Concrete.split_optPervasives.compareesletsplit_ltes=Concrete.split_ltPervasives.compareesletsplit_lees=Concrete.split_lePervasives.compareeslet unions1s2=Concrete.unionPervasives.compares1s2letdiffs1s2=Concrete.diffPervasives.compares1s2letsym_diffs1s2=Concrete.sym_diffPervasives.compares1s2letintersect s1s2=Concrete.interPervasives.compares1s2letcompares1s2=Concrete.comparePervasives.compares1s2let equals1s2=Concrete.equalPervasives.compares1s2letsubset s1s2=Concrete.subsetPervasives.compares1s2letdisjoints1s2=Concrete.disjointPervasives.compares1s2letadd_seqst=Concrete.add_seqPervasives.comparestletof_seqs=Concrete.of_seqPervasives.comparesletto_seqt=Concrete.to_seqtletto_rev_seq t=Concrete.to_rev_seqtletto_seq_from kt=Concrete.to_seq_fromPervasives.comparekt(*$T subset
subset (of_list [1;2;3]) (of_list [1;2;3;4])
not (subset (of_list [1;2;3;5]) (of_list [1;2;3;4]))
not (subset (of_list [1;2;3;4]) (of_list [1;2;3]))
*)(*$T compare
compare (of_list [1;2;3]) (of_list [1;2;3;4]) <> 0
let a = of_list [1;2;3] and b = of_list [1;2;3;4] in compare a b = - (compare b a)
let a = of_list [1;2;3] and b = of_list [1;2;3;4] and c = of_list [3;1;2] in\
compare a b = - (compare b c)
compare (of_list [1;2;3]) (of_list [3;1;2]) = 0
*)(*$T cartesian_product
cartesian_product (of_list [1;2;3]) (of_list ["a"; "b"]) |> to_list = \
[1, "a"; 1, "b"; 2, "a"; 2, "b"; 3, "a"; 3, "b"]
is_empty @@ cartesian_product (of_list [1;2;3]) empty
is_empty @@ cartesian_product empty (of_list [1;2;3])
let s1, s2 = of_list ["a"; "b"; "c"], of_list [1;2;3] in \
equal (cartesian_product s1 s2) \
(map BatTuple.Tuple2.swap (cartesian_product s2 s1))
*)(*$inject
module TestSet =
Set.Make
(struct
type t = int * int
let compare (x, _) (y, _) = BatInt.compare x y
end) ;;
let ts = TestSet.of_list [(1,0);(2,0);(3,0)] ;;
*)(*$T
try ignore(TestSet.update (1, 0) (1, 1) TestSet.empty); false \
with Not_found -> true
TestSet.update (1,0) (1,1) ts = TestSet.of_list [(1,1);(2,0);(3,0)]
TestSet.update (2,0) (2,1) ts = TestSet.of_list [(1,0);(2,1);(3,0)]
TestSet.update (3,0) (3,1) ts = TestSet.of_list [(1,0);(2,0);(3,1)]
TestSet.update (3,0) (-1,0) ts = TestSet.of_list [(1,0);(2,0);(-1,0)]
try ignore (TestSet.update (4,0) (44,00) ts); false with Not_found -> true
*)moduleIncubator=struct(*$< Incubator *)letop_mapfs=Concrete.op_mapfs(*$T op_map
of_enum (1--3) |> op_map ((+) 2) |> mem 5
of_enum (1--3) |> op_map ((+) 2) |> mem 4
of_enum (1--3) |> op_map ((+) 2) |> mem 3
*)end(*$>*)