123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141(** Scoping environment for variables. *)openLplibopenTerm(** Type of an environment, used in scoping to associate names to
corresponding Bindlib variables and types. Note that it cannot be
implemented by a map as the order is important. The structure is similar
to then one of {!type:Term.ctxt}, a tuple [(x,a,t)] is a variable [x],
its type [a] and possibly its definition [t] *)typeenv=(string*(tvar*tbox*tboxoption))listtypet=env(** [empty] is the empty environment. *)letempty:env=[](** [add v a t env] extends the environment [env] by mapping the string
[Bindlib.name_of v] to [(v,a,t)]. *)letadd:tvar->tbox->tboxoption->env->env=funvatenv->(Bindlib.name_ofv,(v,a,t))::env(** [find n env] returns the Bindlib variable associated to the variable name
[n] in the environment [env]. If none is found, [Not_found] is raised. *)letfind:string->env->tvar=funnenv->let(x,_,_)=List.assocnenvinx(** [mem n env] returns [true] iff [n] is mapped to a variable in [env]. *)letmem:string->env->bool=List.mem_assoc(** [to_prod env t] builds a sequence of products / let-bindings whose domains
are the variables of the environment [env] (from left to right), and whose
body is the term [t]. By calling [to_prod [(xn,an,None);⋯;(x1,a1,None)] t]
you obtain a term of the form [Πx1:a1,..,Πxn:an,t]. *)letto_prod_box:env->tbox->tbox=funenvt->letadd_prodt(_,(x,a,u))=letb=Bindlib.bind_varxtinmatchuwith|Someu->_LLetaub|None->_ProdabinList.fold_leftadd_prodtenv(** [to_prod] is an “unboxed” version of [to_prod_box]. *)letto_prod:env->tbox->term=funenvt->Bindlib.unbox(to_prod_boxenvt)(** [to_abst env t] builds a sequence of abstractions or let bindings,
depending on the definition of the elements in the environment whose
domains are the variables of the environment [env] (from left to right),
and which body is the term [t]:
[to_abst [(xn,an,None);..;(x1,a1,None)] t = λx1:a1,..,λxn:an,t]. *)letto_abst:env->tbox->term=funenvt->letadd_abstt(_,(x,a,u))=letb=Bindlib.bind_varxtinmatchuwith|Someu->_LLetaub|None->_AbstabinBindlib.unbox(List.fold_leftadd_absttenv)(** [vars env] extracts the array of the {e not defined} Bindlib variables in
[env]. Note that the order is reversed: [vars [(xn,an);..;(x1,a1)] =
[|x1;..;xn|]]. *)letvars:env->tvararray=funenv->letf(_,(x,_,u))=ifu=NonethenSome(x)elseNoneinArray.of_list(List.filter_rev_mapfenv)(** [appl t env] applies [t] to the variables of [env]. *)letappl:tbox->env->tbox=funtenv->List.fold_right(fun(_,(x,_,_))t->_Applt(_Varix))envt(** [to_tbox env] extracts the array of the {e not defined} variables in [env]
and injects them in the [tbox] type. This is the same as [Array.map _Vari
(vars env)]. Note that the order is reversed: [to_tbox [(xn,an);..;(x1,a1)]
= [|x1;..;xn|]]. *)letto_tbox:env->tboxarray=funenv->letf(_,(x,_,u))=ifu=NonethenSome(_Varix)elseNoneinArray.of_list(List.filter_rev_mapfenv)(** [to_ctxt e] converts an environment into a context. *)letto_ctxt:env->ctxt=List.map(fun(_,(v,a,t))->(v,Bindlib.unboxa,Option.mapBindlib.unboxt))(** [match_prod c t f] returns [f a b] if [t] matches [Prod(a,b)] possibly
after reduction.
@raise [Invalid_argument] if [t] is not a product. *)letmatch_prod:ctxt->term->(term->tbinder->'a)->'a=functf->matchunfoldtwith|Prod(a,b)->fab|_->matchEval.whnfctwith|Prod(a,b)->fab|_->invalid_arg__LOC__(** [of_prod c s t] returns a tuple [(env,b)] where [b] is constructed from
the term [t] by unbinding as much dependent products as possible in the
head of [t]. The free variables created by this process, prefixed by [s],
are given (with their types) in the environment [env] (in reverse
order). For instance, if [t] is of the form [Πx1:a1, ⋯, Πxn:an, b], then
the function returns [b] and the environment [(xn,an); ⋯;(x1,a1)]. *)letof_prod:ctxt->string->term->env*term=funcst->leti=Stdlib.ref(-1)inletrecbuild_envenvt=trymatch_prodct(funab->letname=Stdlib.(incri;s^string_of_int!i)inletx,b=LibTerm.unbind_namenamebinbuild_env(addx(lifta)Noneenv)b)withInvalid_argument_->env,tinbuild_env[]t(** [of_prod_nth c n t] returns a tuple [(env,b)] where [b] is constructed
from the term [t] by unbinding [n] dependent products. The free variables
created by this process are given (with their types) in the environment
[env] (in reverse order). For instance, if [t] is of the form [Πx1:a1, ⋯,
Πxn:an, b] then the function returns [b] and the environment [(xn,an);
⋯;(x1,a1)]. [n] must be non-negative.
@raise [Invalid_argument] if [t] does not evaluate to a series of (at least)
[n] products. *)letof_prod_nth:ctxt->int->term->env*term=funcnt->letrecbuild_envienvt=ifi>=nthenenv,telsematch_prodct(funab->letx,b=Bindlib.unbindbinbuild_env(i+1)(addx(lifta)Noneenv)b)inbuild_env0[]t(** [of_prod_using c xs t] is similar to [of_prod s c n t] where [n =
Array.length xs] except that it replaces unbound variables by those of
[xs].
@raise [Invalid_argument] if [t] does not evaluate to a series of (at least)
[n] products. *)letof_prod_using:ctxt->tvararray->term->env*term=funcxst->letn=Array.lengthxsinletrecbuild_envienvt=ifi>=nthenenv,telsematch_prodct(funab->letenv=addxs.(i)(lifta)Noneenvinbuild_env(i+1)env(Bindlib.substb(mk_Vari(xs.(i)))))inbuild_env0[]t