123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605(* 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->unittype+'at=unit->'anodeand+'anode='aSeq.node=|Nil|Consof'a*'atletnil()=Nilletconsab()=Cons(a,b)letempty=nilletsingletonx()=Cons(x,nil)letrec_foreverx()=Cons(x,_foreverx)letrec_repeatnx()=ifn<=0thenNilelseCons(x,_repeat(n-1)x)letrepeat?nx=matchnwith|None->_foreverx|Somen->_repeatnx(*$T
repeat ~n:4 0 |> to_list = [0;0;0;0]
repeat ~n:0 1 |> to_list = []
repeat 1 |> take 20 |> to_list = (repeat ~n:20 1 |> to_list)
*)letis_emptyl=matchl()with|Nil->true|Cons_->falselethead_exnl=matchl()with|Nil->raiseNot_found|Cons(x,_)->xletheadl=matchl()withNil->None|Cons(x,_)->Somexlettail_exnl=matchl()with|Nil->raiseNot_found|Cons(_,l)->llettaill=matchl()with|Nil->None|Cons(_,l)->Somelletrecequaleql1l2=matchl1(),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=foldletreciterfl=matchl()with|Nil->()|Cons(x,l')->fx;iterfl'letiterifl=letrecauxfli=matchl()with|Nil->()|Cons(x,l')->fix;auxfl'(i+1)inauxfl0letlengthl=fold(funacc_->acc+1)0lletrectaken(l:'at)()=ifn=0thenNilelsematchl()with|Nil->Nil|Cons(x,l')->Cons(x,take(n-1)l')letrectake_whilepl()=matchl()with|Nil->Nil|Cons(x,l')->ifpxthenCons(x,take_whilepl')elseNil(*$T
of_list [1;2;3;4] |> take_while (fun x->x < 4) |> to_list = [1;2;3]
*)letrecdropn(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->res(*$Q
(Q.pair (Q.list Q.small_int) Q.small_int) (fun (l,n) -> \
let s = of_list l in let s1, s2 = take n s, drop n s in \
append s1 s2 |> to_list = l )
*)letrecmapfl()=matchl()with|Nil->Nil|Cons(x,l')->Cons(fx,mapfl')(*$T
(map ((+) 1) (1 -- 5) |> to_list) = (2 -- 6 |> to_list)
*)letmapifl=letrecauxfli()=matchl()with|Nil->Nil|Cons(x,tl)->Cons(fix,auxftl(i+1))inauxfl0(*$T
mapi (fun i x -> i,x) (1 -- 3) |> to_list = [0, 1; 1, 2; 2, 3]
*)letrecfmapf(l:'at)()=matchl()with|Nil->Nil|Cons(x,l')->beginmatchfxwith|None->fmapfl'()|Somey->Cons(y,fmapfl')end(*$T
fmap (fun x -> if x mod 2=0 then Some (x*3) else None) (1--10) |> to_list \
= [6;12;18;24;30]
*)letrecfilterpl()=matchl()with|Nil->Nil|Cons(x,l')->ifpxthenCons(x,filterpl')elsefilterpl'()letrecappendl1l2()=matchl1()with|Nil->l2()|Cons(x,l1')->Cons(x,appendl1'l2)letreccyclel()=appendl(cyclel)()(*$T
cycle (of_list [1;2]) |> take 5 |> to_list = [1;2;1;2;1]
cycle (of_list [1; ~-1]) |> take 100_000 |> fold (+) 0 = 0
*)letrecunfoldfacc()=matchfaccwith|None->Nil|Some(x,acc')->Cons(x,unfoldfacc')(*$T
let f = function 10 -> None | x -> Some (x, x+1) in \
unfold f 0 |> to_list = [0;1;2;3;4;5;6;7;8;9]
*)letrecfor_allpl=matchl()with|Nil->true|Cons(x,tl)->px&&for_allptl(*$T
for_all ((=) 1) (of_list []) = true
for_all ((=) 1) (of_list [0]) = false
for_all ((=) 1) (of_list [1]) = true
for_all ((=) 1) (of_list [1; 0]) = false
for_all ((=) 1) (of_list [0; 1]) = false
for_all ((=) 1) (of_list [1; 1]) = true
let l () = Cons (0, fun () -> failwith "no second element") in \
try ignore (for_all ((=) 1) l); true with Failure _ -> false
*)letrecexistspl=matchl()with|Nil->false|Cons(x,tl)->px||existsptl(*$T
exists ((=) 1) (of_list []) = false
exists ((=) 1) (of_list [0]) = false
exists ((=) 1) (of_list [1]) = true
exists ((=) 1) (of_list [1; 0]) = true
exists ((=) 1) (of_list [0; 1]) = true
exists ((=) 1) (of_list [0; 0]) = false
let l () = Cons (1, fun () -> failwith "no second element") in \
try ignore (exists ((=) 1) l); true with Failure _ -> false
*)letrecflat_mapfl()=matchl()with|Nil->Nil|Cons(x,l')->_flat_map_appf(fx)l'()and_flat_map_appfll'()=matchl()with|Nil->flat_mapfl'()|Cons(x,tl)->Cons(x,_flat_map_appftll')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_lefth1tl1h2tl2()|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[]l2letproductl1l2=product_with(funxy->x,y)l1l2letrecgroupeql()=matchl()with|Nil->Nil|Cons(x,l')->Cons(consx(take_while(eqx)l'),groupeq(drop_while(eqx)l'))(*$T
of_list [1;1;1;2;2;3;3;1] |> group (=) |> map to_list |> to_list = \
[[1;1;1]; [2;2]; [3;3]; [1]]
*)letrec_uniqeqprevl()=matchprev,l()with|_,Nil->Nil|None,Cons(x,l')->Cons(x,_uniqeq(Somex)l')|Somey,Cons(x,l')->ifeqxythen_uniqeqprevl'()elseCons(x,_uniqeq(Somex)l')letuniqeql=_uniqeqNonelletrecfilter_mapfl()=matchl()with|Nil->Nil|Cons(x,l')->beginmatchfxwith|None->filter_mapfl'()|Somey->Cons(y,filter_mapfl')endletflattenl=flat_map(funx->x)lletrangeij=letrecauxij()=ifi=jthenCons(i,nil)elseifi<jthenCons(i,aux(i+1)j)elseCons(i,aux(i-1)j)inauxij(*$T
range 0 5 |> to_list = [0;1;2;3;4;5]
range 0 0 |> to_list = [0]
range 5 2 |> to_list = [5;4;3;2]
*)let(--)=rangelet(--^)ij=ifi=jthenemptyelseifi<jthenrangei(j-1)elserangei(j+1)(*$T
1 --^ 5 |> to_list = [1;2;3;4]
5 --^ 1 |> to_list = [5;4;3;2]
1 --^ 2 |> to_list = [1]
0 --^ 0 |> to_list = []
*)letrecfold2faccl1l2=matchl1(),l2()with|Nil,_|_,Nil->acc|Cons(x1,l1'),Cons(x2,l2')->fold2f(faccx1x2)l1'l2'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'letrecexists2fl1l2=matchl1(),l2()with|Nil,_|_,Nil->false|Cons(x1,l1'),Cons(x2,l2')->fx1x2||exists2fl1'l2'letrecmergecmpl1l2()=matchl1(),l2()with|Nil,tl2->tl2|tl1,Nil->tl1|Cons(x1,l1'),Cons(x2,l2')->ifcmpx1x2<0thenCons(x1,mergecmpl1'l2)elseCons(x2,mergecmpl1l2')letreczipab()=matcha(),b()with|Nil,_|_,Nil->Nil|Cons(x,a'),Cons(y,b')->Cons((x,y),zipa'b')letunzipl=letrecfirstl()=matchl()with|Nil->Nil|Cons((x,_),tl)->Cons(x,firsttl)andsecondl()=matchl()with|Nil->Nil|Cons((_,y),tl)->Cons(y,secondtl)infirstl,secondl(*$Q
Q.(list (pair int int)) (fun l -> \
let l = of_list l in let a, b = unzip l in equal (=) l (zip a b))
*)letzip_iseq=letrecloopiseq()=matchseq()with|Nil->Nil|Cons(x,tl)->Cons((i,x),loop(i+1)tl)inloop0seq(*$=
[0,'a'; 1, 'b'; 2, 'c'] (of_string "abcde" |> zip_i |> take 3 |> to_list)
*)(** {2 Implementations} *)letreturnx()=Cons(x,nil)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);a(*$Q
Q.(array int) (fun a -> of_array a |> to_array = a)
*)(*$T
of_array [| 1; 2; 3 |] |> to_list = [1;2;3]
of_list [1;2;3] |> to_array = [| 1; 2; 3; |]
let r = ref 1 in \
let s = unfold (fun i -> if i < 3 then let x = !r in incr r; Some (x, succ i) else None) 0 in \
to_array s = [| 1; 2; 3; |]
*)letrecto_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->beginmatchg()with|None->r:=Of_gen_savedNil;Nil|Somex->lettl=consume(ref(Of_gen_thunkg))inletl=Cons(x,tl)inr:=Of_gen_savedl;lendinconsume(ref(Of_gen_thunkg))(*$R
let g = let n = ref 0 in fun () -> Some (incr n; !n) in
let l = of_gen g in
assert_equal [1;2;3;4;5;6;7;8;9;10] (take 10 l |> to_list);
assert_equal [1;2;3;4;5;6;7;8;9;10] (take 10 l |> to_list);
assert_equal [11;12] (drop 10 l |> take 2 |> to_list);
*)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(*$R
let printer = Q.Print.(list int) in
let gen () =
let rec l = let r = ref 0 in fun () -> incr r; Cons (!r, l) in l
in
let l1 = gen () in
assert_equal ~printer [1;2;3;4] (take 4 l1 |> to_list);
assert_equal ~printer [5;6;7;8] (take 4 l1 |> to_list);
let l2 = gen () |> memoize in
assert_equal ~printer [1;2;3;4] (take 4 l2 |> to_list);
assert_equal ~printer [1;2;3;4] (take 4 l2 |> to_list);
*)(** {2 Fair Combinations} *)letrecinterleaveab()=matcha()with|Nil->b()|Cons(x,tail)->Cons(x,interleavebtail)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(*$T
interleave (of_list [1;3;5]) (of_list [2;4;6]) |> to_list = [1;2;3;4;5;6]
fair_app (of_list [(+)1; ( * ) 3]) (of_list [1; 10]) \
|> to_list |> List.sort Stdlib.compare = [2; 3; 11; 30]
*)(** {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'inbeginmatchl()with|Nil->()|Cons(x,l')->pp_itemfmtx;ppfmtl'end;pp_stopfmt()