123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637(* This file is free software, part of containers. See file "license" for more details. *)(** {1 Random-Access Lists} *)(** A complete binary tree *)type+'atree=|Leafof'a|Nodeof'a*'atree*'atreeand+'at=|Nil|Consofint*'atree*'at(** Functional array of complete trees *)(** {2 Functions on trees} *)(** {2 Functions on lists of trees} *)letempty=Nilletreturnx=Cons(1,Leafx,Nil)letis_empty=function|Nil->true|Cons_->falseletrecget_exnli=matchlwith|Nil->invalid_arg"RAL.get"|Cons(size,t,_)wheni<size->tree_lookup_sizeti|Cons(size,_,l')->get_exnl'(i-size)andtree_lookup_sizeti=matcht,iwith|Leafx,0->x|Leaf_,_->invalid_arg"RAL.get"|Node(x,_,_),0->x|Node(_,t1,t2),_->letsize'=size/2inifi<=size'thentree_lookup_size't1(i-1)elsetree_lookup_size't2(i-1-size')letgetli=trySome(get_exnli)withInvalid_argument_->Noneletrecsetliv=matchlwith|Nil->invalid_arg"RAL.set"|Cons(size,t,l')wheni<size->Cons(size,tree_update_sizetiv,l')|Cons(size,t,l')->Cons(size,t,setl'(i-size)v)andtree_update_sizetiv=matcht,iwith|Leaf_,0->Leafv|Leaf_,_->invalid_arg"RAL.set"|Node(_,t1,t2),0->Node(v,t1,t2)|Node(x,t1,t2),_->letsize'=size/2inifi<=size'thenNode(x,tree_update_size't1(i-1)v,t2)elseNode(x,t1,tree_update_size't2(i-1-size')v)(*$Q & ~small:(CCFun.compose snd List.length)
Q.(pair (pair small_int int) (list int)) (fun ((i,v),l) -> \
l=[] || \
(let i = (abs i) mod (List.length l) in \
let ral = of_list l in let ral = set ral i v in \
get_exn ral i = v))
*)(*$Q & ~small:List.length
Q.(list small_int) (fun l -> \
let l1 = of_list l in \
CCList.mapi (fun i x -> i,x) l \
|> List.for_all (fun (i,x) -> get_exn l1 i = x))
*)letconsxl=matchlwith|Cons(size1,t1,Cons(size2,t2,l'))whensize1=size2->Cons(1+size1+size2,Node(x,t1,t2),l')|_->Cons(1,Leafx,l)letcons'lx=consxllethdl=matchlwith|Nil->invalid_arg"RAL.hd"|Cons(_,Leafx,_)->x|Cons(_,Node(x,_,_),_)->xlettll=matchlwith|Nil->invalid_arg"RAL.tl"|Cons(_,Leaf_,l')->l'|Cons(size,Node(_,t1,t2),l')->letsize'=size/2inCons(size',t1,Cons(size',t2,l'))(*$T
let l = of_list[1;2;3] in hd l = 1
let l = of_list[1;2;3] in tl l |> to_list = [2;3]
*)(*$Q
Q.(list_of_size Gen.(1--100) int) (fun l -> \
let l' = of_list l in \
(not (is_empty l')) ==> (equal ~eq:CCInt.equal l' (cons (hd l') (tl l'))) )
*)letfrontl=matchlwith|Nil->None|Cons(_,Leafx,tl)->Some(x,tl)|Cons(size,Node(x,t1,t2),l')->letsize'=size/2inSome(x,Cons(size',t1,Cons(size',t2,l')))letfront_exnl=matchlwith|Nil->invalid_arg"RAL.front_exn"|Cons(_,Leafx,tl)->x,tl|Cons(size,Node(x,t1,t2),l')->letsize'=size/2inx,Cons(size',t1,Cons(size',t2,l'))letrec_removeprefixli=letx,l'=front_exnlinifi=0thenList.fold_left(funlx->consxl)lprefixelse_remove(x::prefix)l'(i-1)letremoveli=_remove[]liletrec_map_treeft=matchtwith|Leafx->Leaf(fx)|Node(x,l,r)->Node(fx,_map_treefl,_map_treefr)letrecmap~fl=matchlwith|Nil->Nil|Cons(i,t,tl)->Cons(i,_map_treeft,map~ftl)letmapi~fl=letrecauxfil=matchlwith|Nil->Nil|Cons(size,t,tl)->Cons(size,aux_tf~sizeit,auxf(i+size)tl)andaux_tf~sizeit=matchtwith|Leafx->Leaf(fix)|Node(x,l,r)->letx=fixinletl=aux_tf~size:(size/2)(i+1)linNode(x,l,aux_tf~size:(size/2)(i+1+size/2)r)inauxf0l(*$QR
Q.small_int (fun n ->
let l = CCList.(0 -- n) in
let l' = of_list l |> mapi ~f:(fun i x ->i,x) in
List.mapi (fun i x->i,x) l = to_list l'
)
*)(*$Q
Q.(pair (list small_int)(fun2 Observable.int Observable.int bool)) (fun (l,f) -> \
let f = Q.Fn.apply f in \
mapi ~f (of_list l) |> to_list = List.mapi f l )
*)letreclengthl=matchlwith|Nil->0|Cons(size,_,l')->size+lengthl'letreciter~fl=matchlwith|Nil->()|Cons(_,Leafx,l')->fx;iter~fl'|Cons(_,t,l')->iter_treetf;iter~fl'anditer_treetf=matchtwith|Leafx->fx|Node(x,t1,t2)->fx;iter_treet1f;iter_treet2fletiteri~fl=letrecauxfil=matchlwith|Nil->()|Cons(size,t,l')->aux_t~sizefit;auxf(i+size)l'andaux_tf~sizeit=matchtwith|Leafx->fix|Node(x,l,r)->fix;letsize'=size/2inaux_t~size:size'f(i+1)l;aux_t~size:size'f(i+1+size')rinauxf0lletrecfold~f~x:accl=matchlwith|Nil->acc|Cons(_,Leafx,l')->fold~f~x:(faccx)l'|Cons(_,t,l')->letacc'=fold_treetaccfinfold~f~x:acc'l'andfold_treetaccf=matchtwith|Leafx->faccx|Node(x,t1,t2)->letacc=faccxinletacc=fold_treet1accfinfold_treet2accfletrecfold_rev~f~x:accl=matchlwith|Nil->acc|Cons(_,Leafx,l')->f(fold_rev~f~x:accl')x|Cons(_,t,l')->letacc=fold_rev~f~x:accl'infold_tree_revtaccfandfold_tree_revtaccf=matchtwith|Leafx->faccx|Node(x,t1,t2)->letacc=fold_tree_revt2accfinletacc=fold_tree_revt1accfinfaccxletrev_map~fl=fold~f:(funaccx->cons(fx)acc)~x:emptyl(*$Q
Q.(list int) (fun l -> \
let f x = x+1 in \
of_list l |> rev_map ~f |> to_list = List.rev_map f l)
*)letrevl=fold~f:cons'~x:emptyl(*$Q
Q.(list small_int) (fun l -> \
let l = of_list l in rev (rev l) = l)
Q.(list small_int) (fun l -> \
let l1 = of_list l in length l1 = List.length l)
*)letappendl1l2=fold_rev~f:(funl2x->consxl2)~x:l2l1(*$Q & ~small:(CCPair.merge (CCFun.compose_binop List.length (+)))
Q.(pair (list int) (list int)) (fun (l1,l2) -> \
append (of_list l1) (of_list l2) = of_list (l1 @ l2))
*)letappend_tree_tl=fold_tree_revtlcons'letfilter~fl=fold_rev~f:(funaccx->iffxthenconsxaccelseacc)~x:emptylletfilter_map~fl=fold_rev~x:emptyl~f:(funaccx->matchfxwith|None->acc|Somey->consyacc)(*$T
of_list [1;2;3;4;5;6] |> filter ~f:(fun x -> x mod 2=0) |> to_list = [2;4;6]
*)letflat_mapfl=fold_rev~x:emptyl~f:(funaccx->letl=fxinappendlacc)(*$Q
Q.(pair (fun1 Observable.int (small_list int)) (small_list int)) (fun (f,l) -> \
let f x = Q.Fn.apply f x in \
let f' x = f x |> of_list in \
of_list l |> flat_map f' |> to_list = CCList.(flat_map f l))
*)letflattenl=fold_rev~f:(funaccl->appendlacc)~x:emptyl(*$T
flatten (of_list [of_list [1]; of_list []; of_list [2;3]]) = \
of_list [1;2;3;]
*)(*$Q
Q.(small_list (small_list int)) (fun l -> \
of_list l |> map ~f:of_list |> flatten |> to_list = CCList.flatten l)
*)letappfunsl=fold_rev~x:emptyfuns~f:(funaccf->fold_rev~x:accl~f:(funaccx->cons(fx)acc))(*$T
app (of_list [(+) 2; ( * ) 10]) (of_list [1;10]) |> to_list = \
[3; 12; 10; 100]
*)type'astack=|St_nil|St_listof'at*'astack|St_treeof'atree*'astackletrecstack_to_list=function|St_nil->Nil|St_list(l,st')->appendl(stack_to_listst')|St_tree(t,st')->append_tree_t(stack_to_listst')letrectakenl=matchlwith|Nil->Nil|Cons(size,t,tl)->ifsize<=nthenappend_tree_t(take(n-size)tl)elsetake_tree_~sizentandtake_tree_~sizent=matchtwith|_whenn=0->Nil|Leafx->consxNil|Node(x,l,r)->letsize'=size/2inifsize'<=n-1thenconsx(append_tree_l(take_tree_~size:size'(n-size'-1)r))elseconsx(take_tree_~size:size'(n-1)l)(*$T
take 3 (of_list CCList.(1--10)) |> to_list = [1;2;3]
take 5 (of_list CCList.(1--10)) |> to_list = [1;2;3;4;5]
take 0 (of_list CCList.(1--10)) |> to_list = []
*)(*$Q
Q.(pair small_int (list int)) (fun (n,l) -> \
of_list l |> take n |> to_list = CCList.take n l)
*)lettake_while~fl=(* st: stack of subtrees *)letrecauxpst=matchstwith|St_nil->Nil|St_list(Nil,st')->auxpst'|St_list(Cons(_,t,tl),st')->auxp(St_tree(t,St_list(tl,st')))|St_tree(Leafx,st')->ifpxthenconsx(auxpst')elseNil|St_tree(Node(x,l,r),st')->ifpxthenconsx(auxp(St_tree(l,St_tree(r,st'))))elseNilinauxf(St_list(l,St_nil))(*$Q
Q.(list int) (fun l -> \
let f x = x mod 7 <> 0 in \
of_list l |> take_while ~f |> to_list = CCList.take_while f l)
Q.(pair (fun1 Observable.int bool) (list int)) (fun (f,l) -> \
let f x = Q.Fn.apply f x in \
of_list l |> take_while ~f |> to_list = CCList.take_while f l)
*)(* drop [n < size] elements from [t] *)letrecdrop_tree_~sizenttail=matchtwith|_whenn=0->tail|Leaf_->assert(n=1);tail|Node(_,left,right)->ifn=1thenappend_tree_left(append_tree_righttail)else(assert(sizemod2=1);letsize_sub=size/2in(* size of subtrees *)letn=n-1inifn=size_subthen(append_tree_righttail(* drop element and left tree *))elseifn<size_subthen((* drop element and part of left tree *)drop_tree_~size:size_subnleft(append_tree_righttail))else((* drop element, left tree, and part of right tree *)drop_tree_~size:size_sub(n-size_sub)righttail))letrecdropnl=matchlwith|_whenn=0->l|Nil->Nil|Cons(size,t,tl)->ifn>=sizethendrop(n-size)tlelsedrop_tree_~sizenttl(*$T
of_list [1;2;3] |> drop 2 |> length = 1
*)(*$Q
Q.(pair small_int (list int)) (fun (n,l) -> \
of_list l |> drop n |> to_list = CCList.drop n l)
*)letdrop_while~fl=letrecauxpst=matchstwith|St_nil->Nil|St_list(Nil,st')->auxpst'|St_list(Cons(_,t,tail),st')->auxp(St_tree(t,St_list(tail,st')))|St_tree(Leafx,st')->ifpxthenauxpst'elseconsx(stack_to_listst')|St_tree(Node(x,l,r)astree,st')->ifpxthenauxp(St_tree(l,St_tree(r,st')))elseappend_tree_tree(stack_to_listst')inauxf(St_list(l,St_nil))(*$T
drop 3 (of_list CCList.(1--10)) |> to_list = CCList.(4--10)
drop 5 (of_list CCList.(1--10)) |> to_list = [6;7;8;9;10]
drop 0 (of_list CCList.(1--10)) |> to_list = CCList.(1--10)
drop 15 (of_list CCList.(1--10)) |> to_list = []
*)(*$Q
Q.(list_of_size Gen.(0 -- 200) int) (fun l -> \
let f x = x mod 10 <> 0 in \
of_list l |> drop_while ~f |> to_list = CCList.drop_while f l)
*)lettake_dropnl=takenl,dropnlletequal~eql1l2=letrecaux~eql1l2=matchl1,l2with|Nil,Nil->true|Cons(size1,t1,l1'),Cons(size2,t2,l2')->size1=size2&&aux_t~eqt1t2&&aux~eql1'l2'|Nil,Cons_|Cons_,Nil->falseandaux_t~eqt1t2=matcht1,t2with|Leafx,Leafy->eqxy|Node(x1,l1,r1),Node(x2,l2,r2)->eqx1x2&&aux_t~eql1l2&&aux_t~eqr1r2|Leaf_,Node_|Node_,Leaf_->falseinaux~eql1l2(*$Q
Q.(pair (list int)(list int)) (fun (l1,l2) -> \
equal ~eq:CCInt.equal (of_list l1) (of_list l2) = (l1=l2))
*)(** {2 Utils} *)letmakenx=letrecauxnaccx=ifn<=0thenaccelseaux(n-1)(consxacc)xinauxnemptyxletrepeatnl=letrecauxnlacc=ifn<=0thenaccelseaux(n-1)l(appendlacc)inauxnlempty(*$Q
Q.(pair small_int (small_list int)) (fun (n,l) -> \
of_list l |> repeat n |> to_list = CCList.(repeat n l))
*)letrangeij=letrecauxijacc=ifi=jthenconsiaccelseifi<jthenauxi(j-1)(consjacc)elseauxi(j+1)(consjacc)inauxijempty(*$T
range 0 3 |> to_list = [0;1;2;3]
range 3 0 |> to_list = [3;2;1;0]
range 17 17 |> to_list = [17]
*)(*$Q
Q.(pair small_int small_int) (fun (i,j) -> \
range i j |> to_list = CCList.(i -- j) )
*)letrange_r_open_ij=ifi=jthenemptyelseifi<jthenrangei(j-1)elserangei(j+1)(*$= & ~printer:CCFormat.(to_string (hbox (list int)))
[1;2;3;4] (1 --^ 5 |> to_list)
[5;4;3;2] (5 --^ 1 |> to_list)
[1] (1 --^ 2 |> to_list)
[] (0 --^ 0 |> to_list)
*)(** {2 Conversions} *)type'asequence=('a->unit)->unittype'agen=unit->'aoptionletadd_listll2=List.fold_left(funaccx->consxacc)l(List.revl2)(*$Q & ~small:(CCPair.merge (CCFun.compose_binop List.length (+)))
Q.(pair (list small_int) (list small_int)) (fun (l1,l2) -> \
add_list (of_list l2) l1 |> to_list = l1 @ l2)
*)letof_listl=add_listemptylletto_listl=fold_rev~f:(funaccx->x::acc)~x:[]l(*$Q
Q.(list int) (fun l -> to_list (of_list l) = l)
*)letadd_arrayla=Array.fold_rightconsalletof_arraya=add_arrayemptyaletto_arrayl=matchlwith|Nil->[||]|Cons(_,Leafx,_)|Cons(_,Node(x,_,_),_)->letlen=lengthlinletarr=Array.makelenxiniteri~f:(funix->Array.setarrix)l;arr(*$Q
Q.(array int) (fun a -> \
of_array a |> to_array = a)
*)letof_seqs=letl=refemptyins(funx->l:=consx!l);rev!lletadd_seqls=letl1=refemptyins(funx->l1:=consx!l1);fold~f:(funaccx->consxacc)~x:l!l1letto_seqlyield=iter~f:yieldl(*$Q & ~small:List.length
Q.(list small_int) (fun l -> \
of_list l |> to_seq |> Iter.to_list = l)
Q.(list small_int) (fun l -> \
Iter.of_list l |> of_seq |> to_list = l)
*)(*$T
add_seq (of_list [3;4]) (Iter.of_list [1;2]) |> to_list = [1;2;3;4]
*)letrecgen_iter_fg=matchg()with|None->()|Somex->fx;gen_iter_fgletadd_genlg=letl1=refemptyingen_iter_(funx->l1:=consx!l1)g;fold~f:(funaccx->consxacc)~x:l!l1letof_geng=add_genemptygletto_genl=letst=Stack.create()in(* stack for tree *)letl=reflin(* tail of list *)letrecnext()=ifStack.is_emptystthenmatch!lwith|Nil->None|Cons(_,t,tl)->l:=tl;Stack.pushtst;next()elsematchStack.popstwith|Leafx->Somex|Node(x,l,r)->Stack.pushrst;Stack.pushlst;Somexinnext(*$Q & ~small:List.length
Q.(list small_int) (fun l -> of_list l |> to_gen |> Gen.to_list = l)
Q.(list small_int) (fun l -> \
Gen.of_list l |> of_gen |> to_list = l)
*)letrecof_list_map~fl=matchlwith|[]->empty|x::l'->lety=fxinconsy(of_list_map~fl')letcompare~cmpl1l2=letreccmp_gen~cmpg1g2=matchg1(),g2()with|None,None->0|Some_,None->1|None,Some_->-1|Somex,Somey->letc=cmpxyinifc<>0thencelsecmp_gen~cmpg1g2incmp_gen~cmp(to_genl1)(to_genl2)(*$Q
Q.(pair (list int)(list int)) (fun (l1,l2) -> \
compare ~cmp:CCInt.compare (of_list l1) (of_list l2) = (Stdlib.compare l1 l2))
*)(** {2 Infix} *)moduleInfix=structlet(@+)=conslet(>>=)lf=flat_mapfllet(>|=)lf=map~fllet(<*>)=applet(--)=rangelet(--^)=range_r_open_endincludeInfix(** {2 IO} *)type'aprinter=Format.formatter->'a->unitletpp?(sep=", ")pp_itemfmtl=letfirst=reftrueiniterl~f:(funx->if!firstthenfirst:=falseelse(Format.pp_print_stringfmtsep;Format.pp_print_cutfmt(););pp_itemfmtx);()