123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991(** Internal representation of terms.
This module contains the definition of the internal representation of
terms, together with smart constructors and low level operation. *)openLplibopenBaseopenExtraopenCommonopenDebugletlog=Logger.make'm'"term""term building"letlog=log.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. *)(** Data of a binder. *)typebinder_info={binder_name:string;binder_bound:bool}typembinder_info={mbinder_name:stringarray;mbinder_bound:boolarray}letpr_bound=D.array(funppfb->ifbthenoutppf"*"elseoutppf"_")(** Type for free variables. *)typevar=int*string(** [compare_vars x y] safely compares [x] and [y]. Note that it is unsafe to
compare variables using [Pervasive.compare]. *)letcompare_vars:var->var->int=fun(i,_)(j,_)->Stdlib.compareij(** [eq_vars x y] safely computes the equality of [x] and [y]. Note that it is
unsafe to compare variables with the polymorphic equality function. *)leteq_vars:var->var->bool=funxy->compare_varsxy=0(** [new_var name] creates a new unique variable of name [name]. *)letnew_var:string->var=letn=Stdlib.ref0infunname->incrn;!n,name(** [new_var_ind s i] creates a new [var] of name [s ^ string_of_int i]. *)letnew_var_ind:string->int->var=funsi->new_var(Escape.add_prefixs(string_of_inti))(** [base_name x] returns the base name of variable [x]. Note that this name
is not unique: two distinct variables may have the same name. *)letbase_name:var->string=fun(_i,n)->n(** [uniq_name x] returns a string uniquely identifying the variable [x]. *)letuniq_name:var->string=fun(i,_)->"v"^string_of_inti(** Sets and maps of variables. *)moduleVar=structtypet=varletcompare=compare_varsendmoduleVarSet=Set.Make(Var)moduleVarMap=Map.Make(Var)(* Type for bound variables. [InSub i] refers to the i-th slot in the
substitution of the parent binder, [InEnv i] refers to the i-th slot in
the closure environment of the parent binder (variables bound by a binder
which is not the direct parent). *)typebvar=InSubofint|InEnvofint(** The priority of an infix operator is a floating-point number. *)typepriority=float(** Notations. *)type'anotation=|NoNotation|Prefixof'a|Postfixof'a|InfixofPratter.associativity*'a|Zero|Succof'anotation(* NoNotation, Prefix or Postfix only *)|Quant|PosOne|PosDouble|PosSuccDouble|IntZero|IntPos|IntNeg(** 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.
Bound variables [Bvar] never appear outside of the current module. They
correspond to the variables bound by a binder above. They are replaced by
[Vari] whenever the binder is destructed (via unbind and the like)
*)typeterm=|Variofvar(** Free variable. *)|Bvarofbvar(** Bound variables. Only used internally. *)|Type(** "TYPE" constant. *)|Kind(** "KIND" constant. *)|Symbofsym(** User-defined symbol. *)|Prodofterm*binder(** Dependent product. *)|Abstofterm*binder(** Abstraction. *)|Applofterm*term(** Term application. *)|Metaofmeta*termarray(** Metavariable application. *)|Pattofintoption*string*termarray(** Pattern variable application (only used in rewriting rules). *)|Wild(** Wildcard (only used for surface matching, never in LHS). *)|Placofbool(** [Plac b] is a placeholder, or hole, for not given terms. Boolean [b] is
true if the placeholder stands for a type. *)|TRefoftermoptionTimed.ref(** Reference cell (used in surface matching, and evaluation with
sharing). *)|LLetofterm*term*binder(** [LLet(a, t, u)] is [let x : a ≔ t in u] (with [x] bound in [u]). *)(** Type for binders, implemented as closures. The bound variables of a
closure term always refer either to a variable bound by the parent binder
or to a slot in the closure environment of the parent binder. No direct
reference to variables bound by an ancestor binder!
In a binder [(bi,u,e)] of arity [n], [Bvar(InSub i)] occurring in the
closure term [u] (with [i < n]) refers to the bound variable at position
[i] in the given substitution (e.g. argument [vs] of msubst), and
[Bvar(InEnv i)] refers to the term [e.(i)]
For instance, the term [λx. λy. x y] is represented as
[Abst(_,(_,Abst(_,(_,Appl(Bvar(InSub 0)|Bvar(InEnv 0)),
[|Bvar(InSub 0)|])),
[||]))]
*)andbinder=binder_info*term*termarrayandmbinder=mbinder_info*term*termarray(** {b NOTE} that a wildcard "_" of the concrete (source code) syntax may have
a different representation depending on the context. 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 decision tree (used for rewriting). *)anddtree=ruleTree_type.dtree(** Representation of a user-defined symbol. *)andsym={sym_expo:expo(** Visibility. *);sym_path:Path.t(** Module in which the symbol is defined. *);sym_name:string(** Name. *);sym_type:termTimed.ref(** Type. *);sym_impl:boollist(** Implicit arguments ([true] meaning implicit). *);sym_prop:prop(** Property. *);sym_nota:floatnotationTimed.ref(** Notation. *);sym_def:termoptionTimed.ref(** Definition with ≔. *);sym_opaq:boolTimed.ref(** Opacity. *);sym_rules:rulelistTimed.ref(** Rewriting rules. *);sym_mstrat:match_strat(** Matching strategy. *);sym_dtree:dtreeTimed.ref(** Decision tree used for matching. *);sym_pos:Pos.popt(** Position in source file of symbol name. *);sym_decl_pos:Pos.popt(** Position in source file of symbol declaration
without its definition. *)}(** {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). *);names:stringarray(** Names of pattern variables. *);rhs:term(** 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_nb:int(** Number of variables in [lhs]. *);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} {!field:arity} gives the number of arguments contained in the
LHS. It is always equal to [List.length r.lhs] and 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. *)(** All variables of rewriting rules that appear in the RHS must appear in the
LHS. 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. *)(** 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].
During this process, a pattern of
the form {!constructor:Patt}[(Some i,_,_)] 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 [subst_patt env r.rhs]
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:termTimed.ref(** Type. *);meta_arity:int(** Arity (environment size). *);meta_value:mbinderoptionTimed.ref(** Definition. *)}letbinder_name:binder->string=fun(bi,_,_)->bi.binder_nameletmbinder_names:mbinder->stringarray=fun(bi,_,_)->bi.mbinder_name(** [mbinder_arity b] gives the arity of the [mbinder]. *)letmbinder_arity:mbinder->int=fun(i,_,_)->Array.lengthi.mbinder_name(** [binder_occur b] tests whether the bound variable occurs in [b]. *)letbinder_occur:binder->bool=fun(bi,_,_)->bi.binder_boundletmbinder_occur:mbinder->int->bool=fun(bi,_,_)i->assert(i<Array.lengthbi.mbinder_name);bi.mbinder_bound.(i)(** 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))(** [create_sym path expo prop mstrat opaq name pos 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], declaration position [pos], no
definition and no rules. *)letcreate_sym:Path.t->expo->prop->match_strat->bool->Pos.strloc->Pos.popt->term->boollist->sym=funsym_pathsym_exposym_propsym_mstratsym_opaq{elt=sym_name;pos=sym_pos}sym_decl_postypsym_impl->letopenTimedin{sym_path;sym_name;sym_type=reftyp;sym_impl;sym_def=refNone;sym_opaq=refsym_opaq;sym_rules=ref[];sym_nota=refNoNotation;sym_dtree=refTree_type.empty_dtree;sym_mstrat;sym_prop;sym_expo;sym_pos;sym_decl_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|_->Timed.(!(s.sym_opaq))(** [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(** 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)(** [is_unset m] returns [true] if [m] is not instantiated. *)letis_unset:meta->bool=funm->Timed.(!(m.meta_value))=None(** Sets and maps of metavariables. *)moduleMeta=structtypet=metaletcomparem1m2=m2.meta_key-m1.meta_keyendmoduleMetaSet=Set.Make(Meta)moduleMetaMap=Map.Make(Meta)(** Dealing with AC-normalization of terms *)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@[t]] 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)(** Printing functions for debug. *)letrecterm:termpp=funppft->matchunfoldtwith|Bvar(InSubk)->outppf"`%d"k|Bvar(InEnvk)->outppf"~%d"k|Variv->varppfv|Type->outppf"TYPE"|Kind->outppf"KIND"|Symbs->symppfs|Prod(a,(n,b,e))->outppf"(Π %s: %a, %a#(%a))"n.binder_nametermaclos_envetermb|Abst(a,(n,b,e))->outppf"(λ %s: %a, %a#(%a))"n.binder_nametermaclos_envetermb|Appl(a,b)->outppf"(%a %a)"termatermb|Meta(m,ts)->outppf"?%d%a"m.meta_keytermsts|Patt(i,s,ts)->outppf"$%a_%s%a"(D.optionD.int)istermsts|Plac(_)->outppf"_"|Wild->outppf"_"|TRefr->outppf"&%a"(Option.ppterm)Timed.(!r)|LLet(a,t,(n,b,e))->outppf"let %s : %a ≔ %a in %a#(%a)"n.binder_nametermatermtclos_envetermbandvar:varpp=funppf(i,n)->outppf"%s%d"niandsym:sympp=funppfs->stringppfs.sym_nameandterms:termarraypp=funppfts->ifArray.lengthts>0thenD.arraytermppftsandclos_env:termarraypp=funppfenv->D.arraytermppfenv(** [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 can be neither an instantiated metavariable
nor a reference cell ({!constructor:TRef} constructor). Note
that the returned value is physically equal to [t] if no unfolding was
performed. {b NOTE} that {!val:unfold} must (almost) always be called
before matching over a value of type {!type:term}. *)andunfold:term->term=funt->letopenTimedinmatchtwith|Meta(m,ts)->beginmatch!(m.meta_value)with|None->t|Some(b)->unfold(msubstbts)end|TRef(r)->beginmatch!rwith|None->t|Some(v)->unfoldvend|_->t(** [msubst b vs] substitutes the variables bound by [b] with the values
[vs]. Note that the length of the [vs] array should match the arity of
the multiple binder [b]. *)andmsubst:mbinder->termarray->term=fun(bi,tm,env)vs->letn=Array.lengthbi.mbinder_nameinassert(Array.lengthvs=n);letrecmsubstt=(* if Logger.log_enabled() then
log "msubst %a %a" (D.array term) vs term t;*)matchunfoldtwith|Bvar(InSubp)->assertbi.mbinder_bound.(p);vs.(p)|Bvar(InEnvp)->env.(p)|Appl(a,b)->mk_Appl(msubsta,msubstb)(* No need to substitute in the closure term: all bound variables appear
in the closure environment *)|Abst(a,(n,u,e))->Abst(msubsta,(n,u,Array.mapmsubste))|Prod(a,(n,u,e))->Prod(msubsta,(n,u,Array.mapmsubste))|LLet(a,t,(n,u,e))->LLet(msubsta,msubstt,(n,u,Array.mapmsubste))|Meta(m,ts)->Meta(m,Array.mapmsubstts)|Patt(j,n,ts)->Patt(j,n,Array.mapmsubstts)|Type|Kind|Vari_|Wild|Symb_|Plac_|TRef_->tinletr=ifArray.for_all((=)false)bi.mbinder_bound&&Array.lengthenv=0thentmelsemsubsttminifLogger.log_enabled()thenlog"msubst %a#%a %a = %a"clos_envenvtermtm(D.arrayterm)vstermr;r(** Total order on terms. *)andcmp:termcmp=funtt'->matchunfoldt,unfoldt'with|Varix,Varix'->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')|Bvari,Bvarj->Stdlib.compareij|TRefr,TRefr'->Stdlib.comparerr'|LLet(a,t,u),LLet(a',t',u')->lex3cmpcmpcmp_binder(a,t,u)(a',t',u')|t,t'->cmp_tagtt'andcmp_binder:bindercmp=(* fun ({binder_name;binder_bound},u,e) (bi',u',e') ->
let mbi = {mbinder_name=[|binder_name|];mbinder_bound=[|binder_bound|]} in
let var = Vari(new_var binder_name) in
cmp (msubst (mbi,u,e)[|var|])
(msubst({mbi with mbinder_bound=[|bi'.binder_bound|]},u',e')[|var|])*)fun(_,u,e)(_,u',e')->lexcmp(Array.cmpcmp)(u,e)(u',e')(** [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. *)andget_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. *)andget_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(** [is_symb s t] tests whether [t] is of the form [Symb(s)]. *)andis_symb:sym->term->bool=funst->matchunfoldtwithSymb(r)->r==s|_->false(* 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. *)(** [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]. *)andleft_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]. *)andright_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"right_aliens %a %a = %a"symstermt(D.listterm)r;r(** [mk_Appl t u] puts the application of [t] to [u] in canonical form wrt C
or AC symbols. *)andmk_Appl:term*term->term=fun(t,u)->(* if Logger.log_enabled () then
log "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 "mk_Appl(%a, %a) = %a" term t term u term r;
r *)(* unit test *)let_=lets=create_sym[]Privat(ACtrue)Eagerfalse(Pos.none"+")NoneKind[]inlett1=Vari(new_var"x1")inlett2=Vari(new_var"x2")inlett3=Vari(new_var"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])(** [is_abst t] returns [true] iff [t] is of the form [Abst _]. *)letis_abstt=matchunfoldtwithAbst_->true|_->false(** [is_prod t] returns [true] iff [t] is of the form [Prod _]. *)letis_prodt=matchunfoldtwithProd_->true|_->false(** [is_tref t] returns [true] iff [t] is of the form [TRef _]. *)letis_TReft=matchunfoldtwithTRef_->true|_->false(** [iter_atoms db f g t] applies f to every occurrence of a variable in t,
g to every occurrence of a symbol, and db to every occurrence of a
bound variable.
We have to be careful with binders since in the current implementation
closure environment may contain slots for variables that don't actually
appear. This is done by first checking the closure term, recording which
bound variables actually occur, and then check the elements of the
closure environment which occur.
*)letreciter_atoms:(bvar->unit)->(var->unit)->(sym->unit)->term->unit=fundbfgt->letreccheckdbt=matchunfoldtwith|Varix->fx|Symbs->gs|Bvari->dbi|Appl(a,b)->checkdba;checkdbb|Abst(a,b)|Prod(a,b)->checkdba;check_binderdbb|LLet(a,t,b)->checkdba;checkdbt;check_binderdbb|Meta(_,ts)|Patt(_,_,ts)->Array.iter(checkdb)ts|_->()andcheck_binderdb(_bi,u,env)=iter_atoms_closuredbfguenvincheckdbtanditer_atoms_closure:(bvar->unit)->(var->unit)->(sym->unit)->term->termarray->unit=fundbfguenv->(* env positions occuring in [u] *)letu_pos=refIntSet.emptyinletdb_udb=matchdbwith|InEnvp->u_pos:=IntSet.addp!u_pos|_->()in(* We iterate on u, recording which env positions occur *)iter_atomsdb_ufgu;(* We then iterate on the members of [e] that *actually* occur in u *)Array.iteri(funit->ifIntSet.memi!u_postheniter_atomsdbfgt(*else if t <> Wild then env.(i) <- Wild*))envletiter_atoms_mbinder:(bvar->unit)->(var->unit)->(sym->unit)->mbinder->unit=fundbfg(_bi,u,env)->iter_atoms_closuredbfguenv(** [occur x t] tells whether variable [x] occurs in [t]. *)letoccur:var->term->bool=funxt->tryiter_atoms(fun_->())(funy->ifx==ythenraiseExit)(fun_->())t;falsewithExit->trueletoccur_mbinder:var->mbinder->bool=funxb->tryiter_atoms_mbinder(fun_->())(funy->ifx==ythenraiseExit)(fun_->())b;falsewithExit->true(** [is_closed t] checks whether [t] is closed (w.r.t. variables). We have to
be careful with binders since in the current implementation closure
environment may contain slots for variables that don't actually appear *)letis_closed:term->bool=funt->tryiter_atoms(fun_->())(fun_->raiseExit)(fun_->())t;truewithExit->falseletis_closed_mbinder:mbinder->bool=funb->tryiter_atoms_mbinder(fun_->())(fun_->raiseExit)(fun_->())b;truewithExit->false(** [subst b v] substitutes the variable bound by [b] with the value [v].
Assumes v is closed (since only called from outside the term library. *)letsubst:binder->term->term=fun(bi,tm,env)v->letrecsubstt=matchunfoldtwith|Bvar(InSub_)->assertbi.binder_bound;v|Bvar(InEnvp)->env.(p)|Appl(a,b)->mk_Appl(substa,substb)|Abst(a,(n,u,e))->Abst(substa,(n,u,Array.mapsubste))|Prod(a,(n,u,e))->Prod(substa,(n,u,Array.mapsubste))|LLet(a,t,(n,u,e))->LLet(substa,substt,(n,u,Array.mapsubste))|Meta(m,ts)->Meta(m,Array.mapsubstts)|Patt(j,n,ts)->Patt(j,n,Array.mapsubstts)|_->tinletr=ifbi.binder_bound=false&&Array.lengthenv=0thentmelsesubsttminifLogger.log_enabled()thenlog"subst %a#%a [%a] = %a"clos_envenvtermtmtermvtermr;r(** [unbind b] substitutes the binder [b] by a fresh variable of name [name]
if given, or the binder name otherwise. The variable and the result of the
substitution are returned. *)letunbind:?name:string->binder->var*term=fun?(name="")((bn,_,_)asb)->letn=ifname=""thenbn.binder_nameelsenameinletx=new_varninx,substb(Varix)(** [unbind2 f g] is similar to [unbind f], but it substitutes two binders [f]
and [g] at once using the same fresh variable. *)letunbind2:?name:string->binder->binder->var*term*term=fun?(name="")((bn1,_,_)asb1)b2->letn=ifname=""thenbn1.binder_nameelsenameinletx=new_varninx,substb1(Varix),substb2(Varix)(** [unmbind b] substitutes the multiple binder [b] with fresh variables. This
function is analogous to [unbind] for binders. Note that the names used to
create the fresh variables are based on those of the multiple binder. *)letunmbind:mbinder->vararray*term=fun(({mbinder_name=names;_},_,_)asb)->letxs=Array.init(Array.lengthnames)(funi->new_varnames.(i))inxs,msubstb(Array.map(funx->Varix)xs)(** [bind_var x t] binds the variable [x] in [t], producing a binder. *)letbind_var:var->term->binder=fun((_,n)asx)t->letbound=Stdlib.reffalsein(* Replace variables [x] by de Bruijn index [i] *)letrecbindit=(*if Logger.log_enabled() then log "bind_var %d %a" i term t;*)matchunfoldtwith|Variywheny==x->bound:=true;Bvari|Appl(a,b)->leta'=bindiainletb'=bindibinifa==a'&&b==b'thentelseAppl(a',b')(* No need to call mk_Appl here as we only replace free variables by de
Bruijn indices. *)|Abst(a,b)->leta'=bindiainletb'=bind_binderibinifa==a'&&b==b'thentelseAbst(a',b')|Prod(a,b)->leta'=bindiainletb'=bind_binderibinifa==a'&&b==b'thentelseProd(a',b')|LLet(a,m,b)->leta'=bindiainletm'=bindiminletb'=bind_binderibinifa==a'&&m==m'&&b==b'thentelseLLet(a',m',b')|Meta(m,ts)->letts'=Array.map(bindi)tsinifArray.for_all2(==)tsts'thentelseMeta(m,ts')|Patt(j,n,ts)->letts'=Array.map(bindi)tsinifArray.for_all2(==)tsts'thentelsePatt(j,n,ts')|_->tandbind_binderi(bi,u,envasb)=letenv'=Array.map(bindi)envinletj=InEnv(Array.lengthenv')inletu'=bindjuinifu==u'then(* If [u==u'] then x does not occur in u *)ifArray.for_all2(==)envenv'thenbelse(bi,u',env')else(* x occurs, it has been replaced by [Bvar(j)],
corresponding to the head of [e] *)(bi,u',Array.appendenv'[|Bvari|])inletb=bind(InSub0)tinifLogger.log_enabled()thenlog"bind_var %a %a = %a"varxtermttermb;{binder_name=n;binder_bound=!bound},b,[||](** [binder f b] applies f inside [b]. *)letbinder:(term->term)->binder->binder=funfb->letx,t=unbindbinbind_varx(ft)(** [bind_mvar xs t] binds the variables of [xs] in [t] to get a binder.
It is the equivalent of [bind_var] for multiple variables. *)letbind_mvar:vararray->term->mbinder=letempty={mbinder_name=[||];mbinder_bound=[||]}infunxstm->ifArray.lengthxs=0thenempty,tm,[||]elsebegin(*if Logger.log_enabled() then
log "bind_mvar %a" (D.array var) xs;*)lettop_map=Stdlib.refIntMap.emptyandmbinder_bound=Array.make(Array.lengthxs)falseinArray.iteri(funi(ki,_)->Stdlib.(top_map:=IntMap.addkii!top_map))xs;lettop_fvarkey=letp=Stdlib.(IntMap.findkey!top_map)inmbinder_bound.(p)<-true;Bvar(InSubp)in(* Replace variables [x] in [xs] by de Bruijn index [fvar x] *)letrecbindfvart=(*if Logger.log_enabled() then log "bind_mvar %d %a" i term t;*)matchunfoldtwith|Vari(key,_)->ifStdlib.(IntMap.memkey!top_map)thenfvarkeyelset|Appl(a,b)->leta'=bindfvarainletb'=bindfvarbinifa==a'&&b==b'thentelseAppl(a',b')(* No need to call mk_Appl here as we only replace free variables by de
Bruijn indices. *)|Abst(a,b)->leta'=bindfvarainletb'=bind_binderfvarbinifa==a'&&b==b'thentelseAbst(a',b')|Prod(a,b)->leta'=bindfvarainletb'=bind_binderfvarbinifa==a'&&b==b'thentelseProd(a',b')|LLet(a,m,b)->leta'=bindfvarainletm'=bindfvarminletb'=bind_binderfvarbinifa==a'&&m==m'&&b==b'thentelseLLet(a',m',b')|Meta(m,ts)->letts'=Array.map(bindfvar)tsinifArray.for_all2(==)tsts'thentelseMeta(m,ts')|Patt(j,n,ts)->letts'=Array.map(bindfvar)tsinifArray.for_all2(==)tsts'thentelsePatt(j,n,ts')|_->tandbind_binderfvar(bi,u,u_envasb)=letopenStdlibinletu_env'=Array.map(bindfvar)u_envinletu_n=ref0inletu_map=refIntMap.emptyinletfvar'key=matchIntMap.find_optkey!u_mapwith|Somep->Bvar(InEnvp)|None->letp'=Array.lengthu_env'+!u_ninincru_n;u_map:=IntMap.addkeyp'!u_map;Bvar(InEnvp')inletu'=bindfvar'uinifu==u'&&!u_n=0&&Lplib.Array.for_all2(==)u_envu_env'thenbelse(* some vars of [xs] occur in u *)letu_env'=Array.appendu_env'(Array.make!u_nWild)inIntMap.iter(funkeyp->u_env'.(p)<-fvarkey)!u_map;(bi,u',u_env')inletb=bindtop_fvartminifLogger.log_enabled()thenlog"bind_mvar %a %a = %a %a"(D.arrayvar)xstermtmpr_boundmbinder_boundtermb;letbi={mbinder_name=Array.mapbase_namexs;mbinder_bound}inbi,b,[||]end(** 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)], [binder_occur b = true] (useless let's are erased). *)letmk_Varix=Varixletmk_Type=Typeletmk_Kind=Kindletmk_Symbx=Symbxletmk_Prod(a,b)=Prod(a,b)letmk_Arro(a,b)=letx=new_var"_"inProd(a,bind_varxb)letmk_Abst(a,b)=Abst(a,b)letmk_Meta(m,ts)=(*assert (m.meta_arity = Array.length ts);*)Meta(m,ts)letmk_Patt(i,s,ts)=Patt(i,s,ts)letmk_Wild=Wildletmk_Placb=Placbletmk_TRefx=TRefxletmk_LLet(a,t,b)=LLet(a,t,b)(** [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->matchget_argstwith|Symbs,_whenis_modulos->List.fold_left(funtu->mk_Appl(t,u))tts|_->List.fold_left(funtu->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->matchget_argstwith|Symbs,_whenis_modulos->List.fold_left(funtu->mk_Appl(t,fu))tts|_->List.fold_left(funtu->Appl(t,fu))tts(** Patt substitution. *)letsubst_patt:mbinderoptionarray->term->term=funenv->letrecsubst_pattt=matchunfoldtwith|Patt(Somei,n,ts)when0<=i&&i<Array.lengthenv->beginmatchenv.(i)with|Someb->msubstb(Array.mapsubst_pattts)|None->mk_Patt(Somei,n,Array.mapsubst_pattts)end|Patt(i,n,ts)->mk_Patt(i,n,Array.mapsubst_pattts)|Prod(a,(n,b,e))->mk_Prod(subst_patta,(n,subst_pattb,Array.mapsubst_patte))|Abst(a,(n,b,e))->mk_Abst(subst_patta,(n,subst_pattb,Array.mapsubst_patte))|Appl(a,b)->mk_Appl(subst_patta,subst_pattb)|Meta(m,ts)->mk_Meta(m,Array.mapsubst_pattts)|LLet(a,t,(n,b,e))->mk_LLet(subst_patta,subst_pattt,(n,subst_pattb,Array.mapsubst_patte))|Wild|Plac_|TRef_|Bvar_|Vari_|Type|Kind|Symb_->tinsubst_patt(** [cleanup t] unfold all metas and TRef's in [t]. *)letreccleanup:term->term=funt->matchunfoldtwith|Patt(i,n,ts)->mk_Patt(i,n,Array.mapcleanupts)|Prod(a,b)->mk_Prod(cleanupa,bindercleanupb)|Abst(a,b)->mk_Abst(cleanupa,bindercleanupb)|Appl(a,b)->mk_Appl(cleanupa,cleanupb)|Meta(m,ts)->mk_Meta(m,Array.mapcleanupts)|LLet(a,t,b)->mk_LLet(cleanupa,cleanupt,bindercleanupb)|Wild->assertfalse|Plac_->assertfalse|TRef_->assertfalse|Bvar_->assertfalse|Vari_|Type|Kind|Symb_->t(** 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)->r.rhs(** 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(** Typing context associating a 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=(var*term*termoption)listletdeclppf(v,a,d)=outppf"%a: %a"varvterma;matchdwith|None->()|Somed->outppf" ≔ %a"termdletctxt:ctxtpp=funppfc->List.ppdecl", "ppf(List.revc)(** Type of unification constraints. *)typeconstr=ctxt*term*term(** 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_auxTimed.ref(** Create a new empty problem. *)letnew_problem:unit->problem=fun()->Timed.ref{to_solve=[];unsolved=[];recompute=false;metas=MetaSet.empty}(** Printing functions for debug. *)moduleRaw=structletsym=symlet_=symletterm=termlet_=termletctxt=ctxtlet_=ctxtend