123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267(******************************************************************************)(* *)(* Feat *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright Inria. All rights reserved. This file is distributed under the *)(* terms of the MIT license, as described in the file LICENSE. *)(******************************************************************************)(* This is an implementation of implicit finite sequences as syntax, that is,
algebraic data structures. This style should be more efficient than the one
used in IFSeqObj, because fewer memory blocks are allocated (one block per
construct instead of typically three) and because it opens the door to
rebalancing schemes -- e.g., trees of binary [Sum] nodes can be balanced. *)(* In this implementation, the constructors have time complexity O(1),
under the assumption that the arithmetic operations provided by [Z]
cost O(1) as well. *)moduleMake(Z:BigIntSig.BASIC)=structtypeindex=Z.t(* The data constructors [Rev], [Sum], [Product], [Map] are annotated with the
length of the sequence. *)(* The child of [Rev] cannot be [Empty], [Singleton], or [Rev]. *)(* The children of [Sum], [Product], [Map] cannot be [Empty]. *)(* In [Up (a, b)], we require [a < b], so the sequence is nonempty. *)type_seq=|Empty:'aseq|Singleton:'a->'aseq|Rev:index*'aseq->'aseq|Sum:index*'aseq*'aseq->'aseq|Product:index*'aseq*'bseq->('a*'b)seq|Map:index*('a->'b)*'aseq->'bseq|Up:int*int->intseqletis_empty(typea)(s:aseq):bool=matchswith|Empty->true|Singleton_->false|Rev_->false|Sum_->false|Product_->false|Map_->false|Up_->falseletlength(typea)(s:aseq):index=matchswith|Empty->Z.zero|Singleton_->Z.one|Rev(length,_)->length|Sum(length,_,_)->length|Product(length,_,_)->length|Map(length,_,_)->length|Up(a,b)->Z.of_int(b-a)letout_of_bounds()=failwith"Index is out of bounds."letempty=Emptyletzero=emptyletsingletonx=Singletonxletone=singletonletrev(typea)(s:aseq):aseq=matchswith|Empty->s|Singleton_->s|Rev(_,s)->s|Sum_->Rev(lengths,s)|Product_->Rev(lengths,s)|Map_->Rev(lengths,s)|Up_->Rev(lengths,s)letsums1s2=ifis_emptys1thens2elseifis_emptys2thens1elseletlength=Z.add(lengths1)(lengths2)inSum(length,s1,s2)let(++)=sumletproducts1s2=ifis_emptys1||is_emptys2thenemptyelseletlength=Z.mul(lengths1)(lengths2)inProduct(length,s1,s2)let(**)=productletmapphis=ifis_emptysthenemptyelseMap(lengths,phi,s)letupab=ifa<bthen(* We might wish to also check that [b - a] does not overflow. *)Up(a,b)elseEmptyletrecget:typea.aseq->index->a=funsi->matchswith|Empty->out_of_bounds()|Singletonx->ifZ.equaliZ.zerothenxelseout_of_bounds()|Rev(n,s)->gets(Z.sub(Z.predn)i)|Sum(_,s1,s2)->letn1=lengths1inifZ.ltin1thengets1ielsegets2(Z.subin1)|Product(_,s1,s2)->letq,r=Z.div_remi(lengths2)ingets1q,gets2r|Map(_,phi,s)->phi(getsi)|Up(a,b)->matchZ.to_intiwith|exceptionZ.Overflow->out_of_bounds()|i->letx=a+iinifx<a||b<=xthenout_of_bounds()elsexletrecforeach:typea.aseq->bool->(a->unit)->unit=funssensek->matchswith|Empty->()|Singletonx->kx|Rev(_,s)->foreachs(notsense)k|Sum(_,s1,s2)->lets1,s2=ifsensethens1,s2elses2,s1inforeachs1sensek;foreachs2sensek|Product(_,s1,s2)->foreachs1sense(funx1->foreachs2sense(funx2->k(x1,x2)))|Map(_,phi,s)->foreachssense(funx->k(phix))|Up(a,b)->ifsensethenforx=atob-1dokxdoneelseforx=b-1downtoadokxdoneletforeachsf=foreachstruef(* In order to avoid concatenation [Seq.concat] and flattening [Seq.flat_map],
a producer of a sequence of type ['a Seq.t] must be parameterized over a
construction function [cons] and a continuation [k]. Thus, a producer has
a type of the following form: *)type('a,'b)producer=('a->'bSeq.t->'bSeq.t)->'bSeq.t->'bSeq.t(* [interval sense a b] produces the sequence of integers between [a] included
and [b] excluded. If [sense] is [true], this sequence is produced in
ascending order; otherwise, it is produced in descending order. *)letrecintervalsenseab:(int,'b)producer=funconsk->ifa<bthen(* Compute the first element [x] and the parameters [a] and [b]
of the recursive call. *)letx,a,b=ifsensethena,a+1,belseb-1,a,b-1in(* Produce [x] and delay the recursive call. *)consx(fun()->intervalsenseabconsk())elsek(* [to_seq s sense] produces the sequence [s]. If [sense] is [true], then this
sequence is produced in order; otherwise, it is produced in reverse order. *)(* Parameterizing this definition with [cons] and [k] allows us to avoid using
[Seq.concat] and [Seq.flat_map]. Without these parameters, the treatment of
sums and products would require calls to these higher-order functions. *)letrecto_seq:typeab.aseq->bool->(a,b)producer=funssenseconsk->matchswith|Empty->k|Singletonx->consxk|Rev(_,s)->to_seqs(notsense)consk|Sum(_,s1,s2)->lets1,s2=ifsensethens1,s2elses2,s1into_seqs1sensecons(fun()->to_seqs2senseconsk())|Product(_,s1,s2)->to_seqs1sense(funx1k->to_seqs2sense(funx2k->cons(x1,x2)k)k)k|Map(_,phi,s)->to_seqssense(funxk->cons(phix)k)k|Up(a,b)->intervalsenseabconskletconsxxs=fun()->Seq.Cons(x,xs)letto_seqsk=to_seqstrueconskend