123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178(******************************************************************************)(* *)(* Fix *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright Inria. All rights reserved. This file is distributed under the *)(* terms of the GNU Library General Public License version 2, with a *)(* special exception on linking, as described in the file LICENSE. *)(* *)(******************************************************************************)(* A suspension is used to represent a cardinal-that-may-still-be-unknown. *)type'ncardinal=intLazy.t(* The function [cardinal] forces the cardinal to become fixed. *)letcardinal=Lazy.forcetype'nindex=intmoduletypeCARDINAL=sigtypenvaln:ncardinalend(* [Empty] and [Const] produce sets whose cardinal is known. *)moduleEmpty:CARDINAL=structtypenletn=lazy0endmoduleConst(X:sigvalcardinal:intend):CARDINAL=structtypenlet()=assert(X.cardinal>=0)letn=lazyX.cardinalendletconstc:(moduleCARDINAL)=assert(c>=0);(modulestructtypenletn=lazycend)(* [Gensym] produces a set whose cardinal is a priori unknown. A new reference
stores the current cardinal, which grows when [fresh()] is invoked. [fresh]
fails if the suspension [n] has been forced. *)moduleGensym()=structtypenletcounter=ref0letn=lazy!counterletfresh()=assert(not(Lazy.is_valn));letresult=!counterinincrcounter;resultendtype('l,'r)either=|Lof'l|Rof'rmoduletypeSUM=sigtypelandrincludeCARDINALvalinj_l:lindex->nindexvalinj_r:rindex->nindexvalprj:nindex->(lindex,rindex)eitherendmoduleSum(L:CARDINAL)(R:CARDINAL)=structtypentypel=L.ntyper=R.n(* The cardinal [l] of the left-hand set becomes fixed now (if it
wasn't already). We need it to be fixed for our injections and
projections to make sense. *)letl:int=cardinalL.n(* The right-hand set can remain open-ended. *)letr:intcardinal=R.nletn=(* We optimize the case where [r] is fixed already, but the code
in the [else] branch would work always. *)ifLazy.is_valrthenletn=l+cardinalrinlazynelselazy(l+cardinalr)(* Injections. The two sets are numbered side by side. *)letinj_lx=xletinj_ry=l+y(* Projection. *)letprjx=ifx<lthenLxelseR(x-l)endletsum(typelr)(l:lcardinal)(r:rcardinal)=letmoduleL=structtypen=lletn=lendinletmoduleR=structtypen=rletn=rendin(moduleSum(L)(R):SUMwithtypel=landtyper=r)moduleIndex=structtype'nt='nindexletof_int(n:'ncardinal)i:'nindex=letn=cardinalninassert(0<=i&&i<n);iletto_inti=iletiter(n:'ncardinal)(yield:'nindex->unit)=letn=cardinalninfori=0ton-1doyieldidoneexceptionEnd_of_setletenumerate(n:'ncardinal):unit->'nindex=letn=cardinalninletnext=ref0infun()->leti=!nextinifn<=ithenraiseEnd_of_set;incrnext;iendtype('n,'a)vector='aarraymoduleVector=structtype('n,'a)t=('n,'a)vectorletget=Array.unsafe_getletset=Array.unsafe_setletset_constix=setti(x::getti)letlengtha=letn=Array.lengthainlazynletempty=[||]letmake(n:_cardinal)x=letn=cardinalninArray.makenxletmake'(n:_cardinal)f=letn=cardinalninifn=0thenemptyelseArray.maken(f())letinit(n:_cardinal)f=letn=cardinalninArray.initnfletmap=Array.mapend