123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827(** Internal representation of terms.
This module contains the definition of the internal representation of
terms, together with smart constructors and low level operation. The
representation strongly relies on the {!module:Bindlib} library, which
provides a convenient abstraction to work with binders.
@see <https://rlepigre.github.io/ocaml-bindlib/> *)openTimedopenLplibopenBaseopenCommonopenDebugletlog_term=Logger.make'm'"term""term building"letlog_term=log_term.pp(** {3 Term (and symbol) representation} *)(** Representation of a possibly qualified identifier. *)typeqident=Path.t*string(** Pattern-matching strategy modifiers. *)typematch_strat=|Sequen(** Rules are processed sequentially: a rule can be applied only if the
previous ones (in the order of declaration) cannot be. *)|Eager(** Any rule that filters a term can be applied (even if a rule defined
earlier filters the term as well). This is the default. *)(** Specify the visibility and usability of symbols outside their module. *)typeexpo=|Public(** Visible and usable everywhere. *)|Protec(** Visible everywhere but usable in LHS arguments only. *)|Privat(** Not visible and thus not usable. *)(** Symbol properties. *)typeprop=|Defin(** Definable. *)|Const(** Constant. *)|Injec(** Injective. *)|Commu(** Commutative. *)|Assocofbool(** Associative left if [true], right if [false]. *)|ACofbool(** Associative and commutative. *)(** Representation of a term (or types) in a general sense. Values of the type
are also used, for example, in the representation of patterns or rewriting
rules. Specific constructors are included for such applications, and they
are considered invalid in unrelated code. *)typeterm=|Varioftvar(** Free variable. *)|Type(** "TYPE" constant. *)|Kind(** "KIND" constant. *)|Symbofsym(** User-defined symbol. *)|Prodofterm*tbinder(** Dependent product. *)|Abstofterm*tbinder(** Abstraction. *)|Applofterm*term(** Term application. *)|Metaofmeta*termarray(** Metavariable application. *)|Pattofintoption*string*termarray(** Pattern variable application (only used in rewriting rules LHS). *)|TEnvofterm_env*termarray(** Term environment (only used in rewriting rules RHS). *)|Wild|Placofbool|TRefoftermoptionref(** Reference cell (used in surface matching). *)|LLetofterm*term*tbinder(** [LLet(a, t, u)] is [let x : a ≔ t in u] (with [x] bound in [u]). *)(** {b NOTE} that a wildcard "_" of the concrete (source code) syntax may have
a different representation depending on the application. For instance, the
{!constructor:Wild} constructor is only used when matching patterns (e.g.,
with the "rewrite" tactic). In the LHS of a rewriting {!type:rule}, we use
the {!constructor:Patt} constructor to represend wildcards of the concrete
syntax. They are thus considered to be fresh, unused pattern variables. *)(** Representation of a rewriting rule RHS (or action) as given in the type of
rewriting rules (see {!field:Term.rhs}) with the number of variables that
are not in the LHS. In decision trees, a RHS is stored in every leaf since
they correspond to matched rules. *)andrhs=(term_env,term)Bindlib.mbinder(** Representation of a decision tree (used for rewriting). *)anddtree=(rhs*int)Tree_type.dtree(** Representation of a user-defined symbol. Symbols carry a "mode" indicating
whether they may be given rewriting rules or a definition. Invariants must
be enforced for "mode" consistency (see {!type:sym_prop}). *)andsym={sym_expo:expo(** Visibility. *);sym_path:Path.t(** Module in which the symbol is defined. *);sym_name:string(** Name. *);sym_type:termref(** Type. *);sym_impl:boollist(** Implicit arguments ([true] meaning implicit). *);sym_prop:prop(** Property. *);sym_def:termoptionref(** Definition with ≔. *);sym_opaq:bool(** Opacity. *);sym_rules:rulelistref(** Rewriting rules. *);sym_mstrat:match_strat(** Matching strategy. *);sym_dtree:dtreeref(** Decision tree used for matching. *);sym_pos:Pos.popt(** Position in source file. *)}(** {b NOTE} {!field:sym_type} holds a (timed) reference for a technical
reason related to the writing of signatures as binary files (in relation
to {!val:Sign.link} and {!val:Sign.unlink}). This is necessary to
ensure that two identical symbols are always physically equal, even across
signatures. It should NOT be otherwise mutated. *)(** {b NOTE} We maintain the invariant that {!field:sym_impl} never ends with
[false]. Indeed, this information would be redundant. If a symbol has more
arguments than there are booleans in the list then the extra arguments are
all explicit. Finally, note that {!field:sym_impl} is empty if and only if
the symbol has no implicit parameters. *)(** {b NOTE} {!field:sym_prop} restricts the possible
values of {!field:sym_def} and {!field:sym_rules} fields. A symbol is
not allowed to be given rewriting rules (or a definition) when its mode is
set to {!constructor:Constant}. Moreover, a symbol should not be given at
the same time a definition (i.e., {!field:sym_def} different from [None])
and rewriting rules (i.e., {!field:sym_rules} is non-empty). *)(** {b NOTE} For generated symbols (recursors, axioms), {!field:sym_pos} may
not be valid positions in the source. These virtual positions are however
important for exporting lambdapi files to other formats. *)(** {3 Representation of rewriting rules} *)(** Representation of a rewriting rule. A rewriting rule is mainly formed of a
LHS (left hand side), which is the pattern that should be matched for the
rule to apply, and a RHS (right hand side) giving the action to perform if
the rule applies. More explanations are given below. *)andrule={lhs:termlist(** Left hand side (LHS). *);rhs:rhs(** Right hand side (RHS). *);arity:int(** Required number of arguments to be applicable. *);arities:intarray(** Arities of the pattern variables bound in the RHS. *);vars:tevararray(** Bindlib variables used to build [rhs]. The last [xvars_nb] variables
appear only in [rhs]. *);xvars_nb:int(** Number of variables in [rhs] but not in [lhs]. *);rule_pos:Pos.popt(** Position of the rule in the source file. *)}(** {b NOTE} The second parameter of {!constructor:Patt} holds an array of
terms. This is essential for variables binding: using an array of variables
would NOT suffice. *)(** {b NOTE} {!field:arity} gives the number of arguments contained in the
LHS. As a consequence, it is always equal to [List.length r.lhs] and it
gives the minimal number of arguments required to match the LHS. *)(** {b NOTE} For generated rules, {!field:rule_pos} may not be valid positions
in the source. These virtual positions are however important for exporting
lambdapi files to other formats. *)(** The RHS (or action) or a rewriting rule is represented by a term, in which
(higher-order) variables representing "terms with environments" (see the
{!type:term_env} type) are bound. To effectively apply the rewriting rule,
these bound variables must be substituted using "terms with environments"
that are constructed when matching the LHS of the rule. *)(** All variables of rewriting rules that appear in the RHS must appear in the
LHS. This constraint is checked in {!module:Sr}.In the case of unification
rules, we allow variables to appear only in the RHS. In that case, these
variables are replaced by fresh meta-variables each time the rule is used.
The last {!field:terms.rule.xvars} variables of {!field:terms.rule.vars}
are such RHS-only variables. *)(** Representation of a "term with environment", which intuitively corresponds
to a term with bound variables (or a "higher-order" term) represented with
the {!constructor:TE_Some} constructor. Other constructors are included so
that "terms with environments" can be bound in the RHS of rewriting rules.
This is purely technical. *)andterm_env=|TE_Varioftevar(** Free "term with environment" variable (used to build a RHS). *)|TE_Someoftmbinder(** Actual "term with environment" (used to instantiate a RHS). *)|TE_None(** Dummy term environment (used during matching). *)(** The {!constructor:TEnv}[(te,env)] constructor intuitively corresponds to a
term [te] with free variables together with an explicit environment [env].
Note that the binding of the environment actually occurs in [te], when the
constructor is of the form {!constructor:TE_Some}[(b)]. Indeed, [te] holds
a multiple binder [b] that binds every free variables of the term at once.
We then apply the substitution by performing a Bindlib substitution of [b]
with the environment [env]. *)(** During evaluation, we only try to apply rewriting rules when we reduce the
application of a symbol [s] to a list of argument [ts]. At this point, the
symbol [s] contains every rule [r] that can potentially be applied in its
{!field:sym_rules} field. To check if a rule [r] applies, we match the
elements of [r.lhs] with those of [ts] while building an environment [env]
of type {!type:term_env array}. During this process, a pattern of the form
{!constructor:Patt}[(Some i,s,e)] matched against a term [u] will results
in [env.(i)] being set to [u]. If all terms of [ts] can be matched against
corresponding patterns, then environment [env] is fully constructed and it
can hence be substituted in [r.rhs] with [Bindlib.msubst r.rhs env] to get
the result of the application of the rule. *)(** {3 Metavariables and related functions} *)(** Representation of a metavariable, which corresponds to a yet unknown
term typable in some context. The substitution of the free variables
of the context is suspended until the metavariable is instantiated
(i.e., set to a particular term). When a metavariable [m] is
instantiated, the suspended substitution is unlocked and terms of
the form {!constructor:Meta}[(m,env)] can be unfolded. *)andmeta={meta_key:int(** Unique key. *);meta_type:termref(** Type. *);meta_arity:int(** Arity (environment size). *);meta_value:tmbinderoptionref(** Definition. *)}andtbinder=(term,term)Bindlib.binderandtmbinder=(term,term)Bindlib.mbinderandtvar=termBindlib.varandtevar=term_envBindlib.vartypetbox=termBindlib.boxtypetebox=term_envBindlib.box(** Minimize [impl] to enforce our invariant (see {!type:Terms.sym}). *)letminimize_impl:boollist->boollist=letrecrem_falsel=matchlwithfalse::l->rem_falsel|_->linfunl->List.rev(rem_false(List.revl))(** Printing functions for debug. *)moduleRaw=structletrecterm:termpp=funppft->matchtwith|Variv->varppfv|Type->outppf"TYPE"|Kind->outppf"KIND"|Symbs->symppfs|Prod(a,b)->ifBindlib.binder_constantbthenlet_,b=Bindlib.unbindbinoutppf"(%a → %a)"termatermbelseoutppf"(Π %a)"binder(a,b)|Abst(a,b)->outppf"(λ %a)"binder(a,b)|Appl(a,b)->outppf"(%a %a)"termatermb|Meta(m,ts)->outppf"?%a%a"metamtermsts|Patt(i,s,ts)->outppf"$%a_%s%a"(D.optionD.int)istermsts|Plac(_)->outppf"_"|TEnv(te,ts)->outppf"<%a>%a"tenvtetermsts|Wild->outppf"_"|TRefr->outppf"&%a"(Option.ppterm)!r|LLet(a,t,u)->letx,u=Bindlib.unbinduinoutppf"let %a: %a ≔ %a in %a"varxtermatermttermuandterms:termarraypp=funppfts->(*if Array.length ts > 0 then*)D.arraytermppftsandvar:tvarpp=funppfv->outppf"%s"(Bindlib.name_ofv)andbinder:(term*tbinder)pp=funppf(a,b)->letx,b=Bindlib.unbindbinoutppf"%a: %a, %a"varxtermatermbandmeta:metapp=funppfm->outppf"%d"m.meta_keyandsym:sympp=funppfs->outppf"%s"s.sym_nameandtenv:term_envpp=funppfte->matchtewith|TE_Variv->outppf"%s"(Bindlib.name_ofv)|TE_Somemb->letvs,b=Bindlib.unmbindmbinoutppf"%a,%a"(D.arrayvar)vstermb|TE_None->()end(** Typing context associating a [Bindlib] variable to a type and possibly a
definition. The typing environment [x1:A1,..,xn:An] is represented by the
list [xn:An;..;x1:A1] in reverse order (last added variable comes
first). *)typectxt=(tvar*term*termoption)list(** Typing context with lifted terms. Used to optimise type checking and avoid
lifting terms several times. Definitions are not included because these
contexts are used to create meta variables types, which do not use [let]
definitions. *)typebctxt=(tvar*tbox)list(** Type of unification constraints. *)typeconstr=ctxt*term*term(** Sets and maps of term variables. *)moduleVar=structtypet=tvarletcompare=Bindlib.compare_varsendmoduleVarSet=Set.Make(Var)moduleVarMap=Map.Make(Var)(** [of_tvar x] injects the [Bindlib] variable [x] in a term. *)letof_tvar:tvar->term=funx->Vari(x)(** [new_tvar s] creates a new [tvar] of name [s]. *)letnew_tvar:string->tvar=Bindlib.new_varof_tvar(** [new_tvar_ind s i] creates a new [tvar] of name [s ^ string_of_int i]. *)letnew_tvar_ind:string->int->tvar=funsi->new_tvar(Escape.add_prefixs(string_of_inti))(** [of_tevar x] injects the [Bindlib] variable [x] in a {!type:term_env}. *)letof_tevar:tevar->term_env=funx->TE_Vari(x)(** [new_tevar s] creates a new [tevar] with name [s]. *)letnew_tevar:string->tevar=Bindlib.new_varof_tevar(** Sets and maps of symbols. *)moduleSym=structtypet=symletcompares1s2=ifs1==s2then0elsematchStdlib.compares1.sym_names2.sym_namewith|0->Stdlib.compares1.sym_paths2.sym_path|n->nendmoduleSymSet=Set.Make(Sym)moduleSymMap=Map.Make(Sym)(** Sets and maps of metavariables. *)moduleMeta=structtypet=metaletcomparem1m2=m2.meta_key-m1.meta_keyendmoduleMetaSet=Set.Make(Meta)moduleMetaMap=Map.Make(Meta)(** Representation of unification problems. *)typeproblem_aux={to_solve:constrlist(** List of unification problems to solve. *);unsolved:constrlist(** List of unification problems that could not be solved. *);recompute:bool(** Indicates whether unsolved problems should be rechecked. *);metas:MetaSet.t(** Set of unsolved metas. *)}typeproblem=problem_auxref(** Create a new empty problem. *)letnew_problem:unit->problem=fun()->ref{to_solve=[];unsolved=[];recompute=false;metas=MetaSet.empty}(** [create_sym path expo prop opaq name typ impl] creates a new symbol with
path [path], exposition [expo], property [prop], opacity [opaq], matching
strategy [mstrat], name [name.elt], type [typ], implicit arguments [impl],
position [name.pos], no definition and no rules. *)letcreate_sym:Path.t->expo->prop->match_strat->bool->Pos.strloc->term->boollist->sym=funsym_pathsym_exposym_propsym_mstratsym_opaq{elt=sym_name;pos=sym_pos}typsym_impl->{sym_path;sym_name;sym_type=reftyp;sym_impl;sym_def=refNone;sym_opaq;sym_rules=ref[];sym_dtree=refTree_type.empty_dtree;sym_mstrat;sym_prop;sym_expo;sym_pos}(** [is_constant s] tells whether [s] is a constant. *)letis_constant:sym->bool=funs->s.sym_prop=Const(** [is_injective s] tells whether [s] is injective, which is in partiular the
case if [s] is constant. *)letis_injective:sym->bool=funs->matchs.sym_propwithConst|Injec->true|_->false(** [is_private s] tells whether the symbol [s] is private. *)letis_private:sym->bool=funs->s.sym_expo=Privat(** [is_modulo s] tells whether the symbol [s] is modulo some equations. *)letis_modulo:sym->bool=funs->matchs.sym_propwithAssoc_|Commu|AC_->true|_->false(** [unfold t] repeatedly unfolds the definition of the surface constructor of
[t], until a significant {!type:term} constructor is found. The term that
is returned cannot be an instantiated metavariable or term environment nor
a reference cell ({!constructor:TRef} constructor). Note that the returned
value is physically equal to [t] if no unfolding was performed. *)letrecunfold:term->term=funt->matchtwith|Meta(m,ts)->beginmatch!(m.meta_value)with|None->t|Some(b)->unfold(Bindlib.msubstbts)end|TRef(r)->beginmatch!rwith|None->t|Some(v)->unfoldvend|_->t(** {b NOTE} that {!val:unfold} must (almost) always be called before matching
over a value of type {!type:term}. *)(** [is_abst t] returns [true] iff [t] is of the form [Abst(_)]. *)letis_abst:term->bool=funt->matchunfoldtwithAbst(_)->true|_->false(** [is_prod t] returns [true] iff [t] is of the form [Prod(_)]. *)letis_prod:term->bool=funt->matchunfoldtwithProd(_)->true|_->false(** [is_unset m] returns [true] if [m] is not instantiated. *)letis_unset:meta->bool=funm->!(m.meta_value)=None(** [is_symb s t] tests whether [t] is of the form [Symb(s)]. *)letis_symb:sym->term->bool=funst->matchunfoldtwithSymb(r)->r==s|_->false(** Total order on terms. *)letcmp:termcmp=letreccmptt'=matchunfoldt,unfoldt'with|Varix,Varix'->Bindlib.compare_varsxx'|Type,Type|Kind,Kind|Wild,Wild->0|Symbs,Symbs'->Sym.comparess'|Prod(t,u),Prod(t',u')|Abst(t,u),Abst(t',u')->lexcmpcmp_binder(t,u)(t',u')|Appl(t,u),Appl(t',u')->lexcmpcmp(u,t)(u',t')|Meta(m,ts),Meta(m',ts')->lexMeta.compare(Array.cmpcmp)(m,ts)(m',ts')|Patt(i,s,ts),Patt(i',s',ts')->lex3Stdlib.compareStdlib.compare(Array.cmpcmp)(i,s,ts)(i',s',ts')|TEnv(e,ts),TEnv(e',ts')->lexcmp_tenv(Array.cmpcmp)(e,ts)(e',ts')|TRefr,TRefr'->Stdlib.comparerr'|LLet(a,t,u),LLet(a',t',u')->lex3cmpcmpcmp_binder(a,t,u)(a',t',u')|t,t'->cmp_tag(*cmp_map Stdlib.compare prec*)tt'andcmp_bindertt'=let(_,t,t')=Bindlib.unbind2tt'incmptt'andcmp_mbindertt'=let(_,t,t')=Bindlib.unmbind2tt'incmptt'andcmp_tenvee'=matche,e'with|TE_Variv,TE_Variv'->Bindlib.compare_varsvv'|TE_None,TE_None->0|TE_Somet,TE_Somet'->cmp_mbindertt'|_->cmp_tag(*cmp_map Stdlib.compare prec_tenv*)ee'incmp(** [get_args t] decomposes the {!type:term} [t] into a pair [(h,args)], where
[h] is the head term of [t] and [args] is the list of arguments applied to
[h] in [t]. The returned [h] cannot be an [Appl] node. *)letget_args:term->term*termlist=funt->letrecget_argstacc=matchunfoldtwith|Appl(t,u)->get_argst(u::acc)|t->t,accinget_argst[](** [get_args_len t] is similar to [get_args t] but it also returns the length
of the list of arguments. *)letget_args_len:term->term*termlist*int=funt->letrecget_args_lenacclent=matchunfoldtwith|Appl(t,u)->get_args_len(u::acc)(len+1)t|t->(t,acc,len)inget_args_len[]0t(** Construction functions of the private type [term]. They ensure some
invariants:
- In a commutative function symbol application, the first argument is smaller
than the second one wrt [cmp].
- In an associative and commutative function symbol application, the
application is built as a left or right comb depending on the associativity
of the symbol, and arguments are ordered in increasing order wrt [cmp].
- In [LLet(_,_,b)], [Bindlib.binder_constant b = false] (useless let's are
erased). *)letmk_Varix=Varixletmk_Type=Typeletmk_Kind=Kindletmk_Symbx=Symbxletmk_Prod(a,b)=Prod(a,b)letmk_Abst(a,b)=Abst(a,b)letmk_Meta(m,ts)=Meta(m,ts)letmk_Patt(i,s,ts)=Patt(i,s,ts)letmk_Wild=Wildletmk_Placb=Placbletmk_TRefx=TRefxletmk_LLet(a,t,u)=ifBindlib.binder_constantuthenBindlib.substuKindelseLLet(a,t,u)letmk_TEnv(te,ts)=matchtewith|TE_Somemb->Bindlib.msubstmbts|_->TEnv(te,ts)(* We make the equality of terms modulo commutative and
associative-commutative symbols syntactic by always ordering arguments in
increasing order and by putting them in a comb form.
The term [t1 + t2 + t3] is represented by the left comb [(t1 + t2) + t3] if
+ is left associative and [t1 + (t2 + t3)] if + is right associative. *)letmk_binst1t2=Appl(Appl(Symbs,t1),t2)(** [mk_left_comb s t ts] builds a left comb of applications of [s] from
[t::ts] so that [mk_left_comb s t1 [t2; t3] = mk_bin s (mk_bin s t1 t2)
t3]. *)letmk_left_comb:sym->term->termlist->term=funs->List.fold_left(mk_bins)(** [mk_right_comb s ts t] builds a right comb of applications of [s] to
[ts@[p]] so that [mk_right_comb s [t1; t2] t3 = mk_bin s t1 (mk_bin s t2
t3)]. *)letmk_right_comb:sym->termlist->term->term=funs->List.fold_right(mk_bins)(** [left_aliens s t] returns the list of the biggest subterms of [t] not
headed by [s], assuming that [s] is left associative and [t] is in
canonical form. This is the reverse of [mk_left_comb]. *)letleft_aliens:sym->term->termlist=funs->letrecaliensacc=function|[]->acc|u::us->leth,ts=get_argsuinifis_symbshthenmatchtswith|t1::t2::_->aliens(t2::acc)(t1::us)|_->aliens(u::acc)uselsealiens(u::acc)usinfunt->aliens[][t](** [right_aliens s t] returns the list of the biggest subterms of [t] not
headed by [s], assuming that [s] is right associative and [t] is in
canonical form. This is the reverse of [mk_right_comb]. *)letright_aliens:sym->term->termlist=funs->letrecaliensacc=function|[]->acc|u::us->leth,ts=get_argsuinifis_symbshthenmatchtswith|t1::t2::_->aliens(t1::acc)(t2::us)|_->aliens(u::acc)uselsealiens(u::acc)usinfunt->letr=aliens[][t]inifLogger.log_enabled()thenlog_term"right_aliens %a %a = %a"Raw.symsRaw.termt(D.listRaw.term)r;r(* unit test *)let_=lets=create_sym[]Privat(ACtrue)Eagerfalse(Pos.none"+")Kind[]inlett1=Vari(new_tvar"x1")inlett2=Vari(new_tvar"x2")inlett3=Vari(new_tvar"x3")inletleft=mk_bins(mk_binst1t2)t3inletright=mk_binst1(mk_binst2t3)inleteq=eq_of_cmpcmpinassert(eq(mk_left_combst1[t2;t3])left);assert(eq(mk_right_combs[t1;t2]t3)right);leteq=eq_of_cmp(List.cmpcmp)inassert(eq(left_alienssleft)[t1;t2;t3]);assert(eq(right_alienssright)[t3;t2;t1])(** [mk_Appl t u] puts the application of [t] to [u] in canonical form wrt C
or AC symbols. *)letmk_Appl:term*term->term=fun(t,u)->(* if Logger.log_enabled () then
log_term "mk_Appl(%a, %a)" term t term u;
let r = *)matchget_argstwith|Symbs,[t1]->beginmatchs.sym_propwith|Commuwhencmpt1u>0->mk_binsut1|ACtrue->(* left associative symbol *)letts=left_aliensst1andus=left_alienssuinbeginmatchList.sortcmp(ts@us)with|v::vs->mk_left_combsvvs|_->assertfalseend|ACfalse->(* right associative symbol *)letts=right_aliensst1andus=right_alienssuinletvs,v=List.split_last(List.sortcmp(ts@us))inmk_right_combsvsv|_->Appl(t,u)end|_->Appl(t,u)(* in
if Logger.log_enabled () then
log_term "mk_Appl(%a, %a) = %a" term t term u term r;
r *)(** mk_Appl_not_canonical t u] builds the non-canonical (wrt. C and AC
symbols) application of [t] to [u]. WARNING: to use only in Sign.link. *)letmk_Appl_not_canonical:term*term->term=fun(t,u)->Appl(t,u)(** [add_args t args] builds the application of the {!type:term} [t] to a list
arguments [args]. When [args] is empty, the returned value is (physically)
equal to [t]. *)letadd_args:term->termlist->term=funtts->List.fold_left(funtu->mk_Appl(t,u))tts(** [add_args_map f t ts] is equivalent to [add_args t (List.map f ts)] but
more efficient. *)letadd_args_map:term->(term->term)->termlist->term=funtfts->List.fold_left(funtu->mk_Appl(t,fu))tts(** {3 Smart constructors and lifting (related to [Bindlib])} *)(** [_Vari x] injects the free variable [x] into the {!type:tbox} type so that
it may be available for binding. *)let_Vari:tvar->tbox=Bindlib.box_var(** [_Type] injects the constructor [Type] into the {!type:tbox} type. *)let_Type:tbox=Bindlib.boxType(** [_Kind] injects the constructor [Kind] into the {!type:tbox} type. *)let_Kind:tbox=Bindlib.boxKind(** [_Symb s] injects the constructor [Symb(s)] into the {!type:tbox} type. As
symbols are closed object they do not require lifting. *)let_Symb:sym->tbox=funs->Bindlib.box(Symbs)(** [_Appl t u] lifts an application node to the {!type:tbox} type given boxed
terms [t] and [u]. *)let_Appl:tbox->tbox->tbox=Bindlib.box_apply2(funtu->mk_Appl(t,u))(** [_Appl_not_canonical t u] lifts an application node to the {!type:tbox}
type given boxed terms [t] and [u], without putting it in canonical form
wrt. C and AC symbols. WARNING: to use in scoping of rewrite rule LHS only
as it breaks some invariants. *)let_Appl_not_canonical:tbox->tbox->tbox=Bindlib.box_apply2(funtu->Appl(t,u))(** [_Appl_list a [b1;...;bn]] returns (... ((a b1) b2) ...) bn. *)let_Appl_list:tbox->tboxlist->tbox=List.fold_left_Appl(** [_Appl_Symb f ts] returns the same result that
_Appl_l ist (_Symb [f]) [ts]. *)let_Appl_Symb:sym->tboxlist->tbox=funfts->_Appl_list(_Symbf)ts(** [_Prod a b] lifts a dependent product node to the {!type:tbox} type, given
a boxed term [a] for the domain of the product, and a boxed binder [b] for
its codomain. *)let_Prod:tbox->tbinderBindlib.box->tbox=Bindlib.box_apply2(funab->Prod(a,b))let_Impl:tbox->tbox->tbox=letv=new_tvar"_"infunab->_Proda(Bindlib.bind_varvb)(** [_Abst a t] lifts an abstraction node to the {!type:tbox} type, given a
boxed term [a] for the domain type, and a boxed binder [t]. *)let_Abst:tbox->tbinderBindlib.box->tbox=Bindlib.box_apply2(funat->Abst(a,t))(** [_Meta m ts] lifts the metavariable [m] to the {!type:tbox} type given its
environment [ts]. As for symbols in {!val:_Symb}, metavariables are closed
objects so they do not require lifting. *)let_Meta:meta->tboxarray->tbox=funmts->Bindlib.box_apply(funts->Meta(m,ts))(Bindlib.box_arrayts)(** [_Meta_full m ts] is similar to [_Meta m ts] but works with a metavariable
that is boxed. This is useful in very rare cases, when metavariables need
to be able to contain free term environment variables. Using this function
in bad places is harmful for efficiency but not unsound. *)let_Meta_full:metaBindlib.box->tboxarray->tbox=funmts->Bindlib.box_apply2(funmts->Meta(m,ts))m(Bindlib.box_arrayts)(** [_Patt i n ts] lifts a pattern variable to the {!type:tbox} type. *)let_Patt:intoption->string->tboxarray->tbox=funints->Bindlib.box_apply(funts->Patt(i,n,ts))(Bindlib.box_arrayts)(** [_TEnv te ts] lifts a term environment to the {!type:tbox} type. *)let_TEnv:tebox->tboxarray->tbox=funtets->Bindlib.box_apply2(funtets->mk_TEnv(te,ts))te(Bindlib.box_arrayts)(** [_Wild] injects the constructor [Wild] into the {!type:tbox} type. *)let_Wild:tbox=Bindlib.boxWildlet_Plac:bool->tbox=funb->Bindlib.box(mk_Placb)(** [_TRef r] injects the constructor [TRef(r)] into the {!type:tbox} type. It
should be the case that [!r] is [None]. *)let_TRef:termoptionref->tbox=funr->Bindlib.box(TRef(r))(** [_LLet t a u] lifts let binding [let x := t : a in u<x>]. *)let_LLet:tbox->tbox->tbinderBindlib.box->tbox=Bindlib.box_apply3(funatu->mk_LLet(a,t,u))(** [_TE_Vari x] injects a term environment variable [x] into the {!type:tbox}
type so that it may be available for binding. *)let_TE_Vari:tevar->tebox=Bindlib.box_var(** [_TE_None] injects the constructor [TE_None] into the {!type:tbox} type.*)let_TE_None:tebox=Bindlib.boxTE_None(** [lift mk_appl t] lifts the {!type:term} [t] to the type {!type:tbox},
using the function [mk_appl] in the case of an application. This has the
effect of gathering its free variables, making them available for binding.
Bound variable names are automatically updated in the process. *)letlift:(tbox->tbox->tbox)->term->tbox=funmk_appl->letrecliftt=matchunfoldtwith|Varix->_Varix|Type->_Type|Kind->_Kind|Symb_->Bindlib.boxt|Prod(a,b)->_Prod(lifta)(lift_binderb)|Abst(a,t)->_Abst(lifta)(lift_bindert)|Appl(t,u)->mk_appl(liftt)(liftu)|Meta(r,m)->_Metar(Array.mapliftm)|Patt(i,n,m)->_Pattin(Array.mapliftm)|TEnv(te,m)->_TEnv(lift_term_envte)(Array.mapliftm)|Wild->_Wild|Placb->_Placb|TRefr->_TRefr|LLet(a,t,u)->_LLet(lifta)(liftt)(lift_binderu)(* We do not use [Bindlib.box_binder] here because it is possible for a free
variable to disappear from a term through metavariable instantiation. As
a consequence we must traverse the whole term, even when we find a closed
binder, so that the metadata on nested binders is also updated. *)andlift_binderb=letx,t=Bindlib.unbindbinBindlib.bind_varx(liftt)andlift_term_env:term_env->tebox=function|TE_Varix->_TE_Varix|TE_None->_TE_None|TE_Some_->assertfalse(* Unreachable. *)inlift(** [lift t] lifts the {!type:term} [t] to the type {!type:tbox}. This has the
effect of gathering its free variables, making them available for binding.
Bound variable names are automatically updated in the process. *)letlift=lift_Applandlift_not_canonical=lift_Appl_not_canonical(** [bind v lift t] creates a tbinder by binding [v] in [lift t]. *)letbind:tvar->(term->tbox)->term->tbinder=funvliftt->Bindlib.unbox(Bindlib.bind_varv(liftt))letbinds:tvararray->(term->tbox)->term->tmbinder=funvsliftt->Bindlib.unbox(Bindlib.bind_mvarvs(liftt))(** [lift_in c mk_appl t] lifts the {!type:term} [t] in Bindlib context [c] to
the type {!type:tbox}, using the function [mk_appl] in the case of an
application. This has the effect of gathering its free variables, making
them available for binding. Bound variable names are automatically updated
in the process. *)letlift_in:(tbox->tbox->tbox)->Bindlib.ctxt->term->tbox=funmk_appl->letrecliftct=matchunfoldtwith|Varix->_Varix|Type->_Type|Kind->_Kind|Symb_->Bindlib.boxt|Prod(a,b)->_Prod(liftca)(lift_bindercb)|Abst(a,t)->_Abst(liftca)(lift_binderct)|Appl(t,u)->mk_appl(liftct)(liftcu)|Meta(r,m)->_Metar(Array.map(liftc)m)|Patt(i,n,m)->_Pattin(Array.map(liftc)m)|TEnv(te,m)->_TEnv(lift_term_envte)(Array.map(liftc)m)|Wild->_Wild|Placb->_Placb|TRefr->_TRefr|LLet(a,t,u)->_LLet(liftca)(liftct)(lift_bindercu)(* We do not use [Bindlib.box_binder] here because it is possible for a free
variable to disappear from a term through metavariable instantiation. As
a consequence we must traverse the whole term, even when we find a closed
binder, so that the metadata on nested binders is also updated. *)andlift_bindercb=letx,t,c=Bindlib.unbind_incbinBindlib.bind_varx(liftct)andlift_term_env:term_env->tebox=function|TE_Varix->_TE_Varix|TE_None->_TE_None|TE_Some_->assertfalse(* Unreachable. *)inlift(** [cleanup t] builds a copy of the {!type:term} [t] where every instantiated
metavariable, instantiated term environment, and reference cell has been
eliminated using {!val:unfold}. Another effect of the function is that the
the names of bound variables are updated. This is useful to avoid any form
of "visual capture" while printing terms. *)letcleanup:?ctxt:Bindlib.ctxt->term->term=fun?(ctxt=Bindlib.empty_ctxt)t->Bindlib.unbox(lift_in_Appl_not_canonicalctxtt)(** Positions in terms in reverse order. The i-th argument of a constructor
has position i-1. *)typesubterm_pos=intlistletsubterm_pos:subterm_pospp=funppfl->D.(listint)ppf(List.revl)(** Type of critical pair positions (pos,l,r,p,l_p). *)typecp_pos=Pos.popt*term*term*subterm_pos*term(** [term_of_rhs r] converts the RHS (right hand side) of the rewriting rule
[r] into a term. The bound higher-order variables of the original RHS are
substituted using [Patt] constructors. They are thus represented as their
LHS counterparts. This is a more convenient way of representing terms when
analysing confluence or termination. *)letterm_of_rhs:rule->term=funr->letfnix=let(name,arity)=(Bindlib.name_ofx,r.arities.(i))inletvars=Array.initarity(new_tvar_ind"x")inletp=_Patt(Somei)name(Array.map_Varivars)inTE_Some(Bindlib.unbox(Bindlib.bind_mvarvarsp))inBindlib.msubstr.rhs(Array.mapifnr.vars)(** Type of a symbol and a rule. *)typesym_rule=sym*ruleletlhs:sym_rule->term=fun(s,r)->add_args(mk_Symbs)r.lhsletrhs:sym_rule->term=fun(_,r)->term_of_rhsr