Walkthrough

This walkthrough introduces the structure of modular metatheory and the use of Extensibella for proving properties in modular metatheory. Extensibella is an interactive proof assistant that reasons about extensible languages built by separate modules. Much of the reasoning will look familiar to those familiar with Abella.

The language about which we will reason is built by three modules:

We will define these modules using Sterling, our tool for writing extensible languages. Our host language and the let extension are based on the example language in "Sound type-dependent syntactic language extension", a previous paper about proving some aspects of metatheory for more limited extensible languages. Their work has a significantly different character than ours, but we borrow some of their example language here.

Our host language's main property is type preservation, that a well-typed term that takes an evaluation step produces a term with the same type. To prove this, the host language will introduce several other properties it will use as lemmas. Each extension will then contribute to proving these properties. The big step extension will add its own property, that type preservation is also true for its big-step evaluation.

We will close with a discussion of proof composition, how the modular proofs can be used to build full proofs for a composed language.

Readers are encouraged to download the walkthrough skeleton tarball and follow along. Following along will require having Sterling installed to compile the specifications, as well as Extensibella to execute the proof steps. We recommend using Proof General to follow along; if not using Proof General, the commands can be entered into Extensibella on the terminal.

The proof can also be found as part of the examples.

Preparing the Sterling Standard Library for Reasoning

Sterling contains a standard library with useful relations defined for use in writing language specifications, which is included in Sterling modules automatically. It has an accompanying Extensibella module with properties about these relations. To prepare for reasoning about our own modules, we need to compile the Sterling standard library for Extensibella.

To do this, go to the Sterling standard library directory (sterling/stdLib) and run

$ ./build_extensibella
This only needs to be done once to reason about all languages. It should be done again each time Sterling is updated in case the standard library has expanded.

Host Language

We start by writing a specification of our host language in Sterling. This will be the walkthrough:host module. It defines syntax categories and constructors for terms (tm) and types (ty). As discussed in the Sterling tutorial, each type must also declare its projection type.

The host language also declares its relations. It has small-step evaluation (eval), substitution for a variable (subst), a term being a value (value), and typing (typeOf). Each of these has its primary component, explained as part of our view of extensible languages, marked with *. These relations are then defined by inference rules. We also have a special rule, T-Q, that is not part of the language definition but which will play a part in reasoning. We will discuss its use below.

[Reduce File]
Module walkthrough:host

tm ::= var(string)
     | abs(string, ty, tm)
     | app(tm, tm)

Projection tm : [(string, ty)]

ty ::= arrowTy(ty, ty)
     | intTy

Projection ty :



Judgment eval : tm* tm
Judgment subst : string tm tm* tm
Judgment value : tm*

eval T1 T11
----------------------------- [E-App-Step1]
eval app(T1, T2) app(T11, T2)


value T1
eval T2 T21
----------------------------- [E-App-Step2]
eval app(T1, T2) app(T1, T21)


value T2
subst X T2 Body V
-------------------------------- [E-App-Subst]
eval app(abs(X, Ty, Body), T2) V


Extensibella_Stand_In {
  Ctx |{tm}- T ~~> T_T
  eval T_T T2
  -------------------- [E-Q]
  eval T T1
}



X != Y
----------------------- [S-Var-NEq]
subst X R var(Y) var(Y)


------------------ [S-Var-Eq]
subst X R var(X) R


X != Y
subst X R B S
------------------------------------- [S-Abs-NEq]
subst X R abs(Y, Ty, B) abs(Y, Ty, S)


------------------------------------- [S-Abs-Eq]
subst X R abs(X, Ty, B) abs(X, Ty, B)


subst X R T1 S1
subst X R T2 S2
--------------------------------- [S-App]
subst X R app(T1, T2) app(S1, S2)



------------------- [V-Abs]
value abs(X, Ty, T)



Judgment typeOf : [(string, ty)] tm* ty

lookup Ctx X Ty
-------------------- [T-Var]
typeOf Ctx var(X) Ty


typeOf (X, Ty1)::Ctx Body Ty2
---------------------------------------------- [T-Abs]
typeOf Ctx abs(X, Ty1, Body) arrowTy(Ty1, Ty2)


typeOf Ctx T1 arrowTy(Ty1, Ty2)
typeOf Ctx T2 Ty1
------------------------------- [T-App]
typeOf Ctx app(T1, T2) Ty2

In order to reason about this module using Extensibella, we must have Sterling compile it for Extensibella. We can do this by running the following command from the directory containing the contents of the tarball:

$ sterling --extensibella walkthrough:host
This has Sterling translate the inference-rule-based definition into one in Extensibella's specification format and places it where Extensibella can find it.

Properties for the Host Language

The host language's properties can be found in the host/host.xthm file, with the full file, including proofs, reproduced here:

host.xthm [Reduce File]
Module walkthrough:host.

Extensible_Theorem
  typeOf_unique : forall Ctx T TyA TyB,
    TyA : typeOf Ctx T TyA ->
    TyB : typeOf Ctx T TyB ->
    TyA = TyB
  on TyA. [Show Proof]



Extensible_Theorem
  ty_lookup : forall Ctx1 Ctx2 T Ty,
    Ty : typeOf Ctx1 T Ty ->
    L : (forall X XTy, lookup Ctx1 X XTy -> lookup Ctx2 X XTy) ->
    typeOf Ctx2 T Ty
  on Ty. [Show Proof]



Theorem empty_ty_any : forall T Ty Ctx,
  typeOf [] T Ty -> typeOf Ctx T Ty. [Show Proof]



Extensible_Theorem
  subst_type_preservation : forall T Ctx X XTy Ty R S,
    TTy : typeOf ((X, XTy)::Ctx) T Ty ->
    S : subst X R T S ->
    RTy : typeOf [] R XTy ->
    typeOf Ctx S Ty
  on S. [Show Proof]



Extensible_Theorem
  type_preservation : forall T Ty T',
    Ty : typeOf [] T Ty ->
    Ev : eval T T' ->
    typeOf [] T' Ty
  on Ev. [Show Proof]



Projection_Constraint proj_type_same : forall G T Ty T_T,
  G |{tm}- T ~~> T_T -> typeOf G T Ty -> typeOf G T_T Ty.


Ext_Size eval T T'.

Proj_Rel eval T T'.

Ext_Ind forall G T T' Ty, eval T T' with Ty : typeOf G T Ty. [Show Proof]

We will look at each top-level declaration here in turn.

The first element is the module declaration. This lets Extensibella know about which language module we will be reasoning so it can locate and load the specification Sterling wrote.

The remainder of the top-level declarations in the file are properties to prove.

Extensible Theorems

The first couple of declarations are extensible theorems, declared with Extensible_Theorem. Extensible theorems have their proofs organized around the definition of a key relation, identified by the on part of the declaration. For example, for the typeOf_unique property, the first one in the file, its key relation is the typeOf relation, and we are specifically focused on the first derivation of it, typeOf Ctx T TyA, given the named TyA by prefixing it with TyA :. The proof of the extensible theorem proceeds using induction and case analysis on the key relation. For the typeOf_unique property, this means we have top-level proof cases for when typeOf Ctx T TyA is derived by the T-Var, T-Abs, and T-App rules. Showing the proof in the file above will show these cases and their proofs.

The key point to note for extensible theorems is that the set of rules defining the key relation may grow by other extensions adding new rules, as our let extension will do. This is whence the extensible in extensible theorems arises. Extensions to the host language, like the let extension, will know the property exists and what its key relation is, so they can contribute to the proof, adding the proofs for the new cases they introduce.

We will leave the proofs of typeOf_unique and ty_lookup as exercises. For now, they can be skipped. The proof skeleton files have the appropriate number of skip commands for each. These can either be processed in Proof General without changes, or the commands can be copied to Extensibella on the commandline. Note, in the latter case, that each command must be entered on its own line; multiple commands on one line will not be accepted.

Non-Extensible Theorems

Our file contains one non-extensible theorem, declared with Theorem, empty_ty_any, stating that a term typable with an empty context is typable with any context. This particular non-extensible theorem is a corollary of the extensible ty_lookup theorem.

Non-extensible theorems do not have proofs organized around the definitions of extensible relations, so extensions cannot add new proof cases to them. Their full proofs can thus be given in a single module, as we do here.

We also leave the proof of empty_ty_any as an exercise. It can be skipped as the extensible theorems were.

Type Preservation

Type preservation, the main property our host language wants, is an extensible theorem with evaluation as its key relation. In the context of the host language, this gives us proof cases for the E-App-Step1, E-App-Step2, and E-App-Subst rules. As with the typeOf_unique property at which we looked earlier, type preservation may have new proof cases added by extensions and for which they will need to give their own proofs. We will go through the proof of it here. Note we are also leaving subst_type_preservation as an exercise, so it can be skipped as the others were.

We state our type preservation property as a term being typable with an empty typing context and it taking an evaluation step to T' means T' has the same type. We give each assumption a name we will use to refer to it in the proof. The clause on Ev declares we will prove the property by induction on the derivation of evaluation, the property's key relation, and by considering the last rule by which the evaluation might have been derived:

 < Extensible_Theorem
     type_preservation : forall T Ty T',
       Ty : typeOf [] T Ty ->
       Ev : eval T T' ->
       typeOf [] T' Ty
     on Ev.
Subgoal 1:

Variables: Ty T2 T11 T1
IH : forall T Ty T', typeOf [] T Ty -> eval T T' * -> typeOf [] T' Ty
Ty : typeOf [] (app T1 T2) Ty
Ev : eval (app T1 T2) (app T11 T2) @
Ev1 : eval T1 T11 *
============================
 typeOf [] (app T11 T2) Ty 

After declaring the property, we are immediately dropped into the case for the first rule, which here is the E-App-Step1 rule. Before going into how we prove this case, consider our induction scheme. Note we have the inductive hypothesis in the context, using the name IH, in addition to the Ty and Ev assumptions from our declared property. The second premise of IH, corresponding to Ev in our original statement, is marked with the * annotation, while the Ev assumption is marked with the @ assumption. The @ annotation denotes this is the size of derivation with which we started, while the * annotation denotes a smaller derivation. Thus the inductive hypothesis can only be used with derivations marked as smaller. We get smaller derivations by case analysis on derivations annotated with @ or *. We see this in Ev1, coming from the top-level case analysis on the rules deriving Ev.

In this case, for rule E-App-Step1, we evaluate the application by evaluating the first sub-term. The evaluation of the sub-term is smaller, so we can use it with the inductive hypothesis, but first we need a relevant typing derivation. The top-level case analysis on Ev filled in the primary component of Ty, so we can analyze the rules by which this may have been derived using the case tactic:

 < Ty: case Ty.
Subgoal 1:

Variables: Ty T2 T11 T1 Ty1
IH : forall T Ty T', typeOf [] T Ty -> eval T T' * -> typeOf [] T' Ty
Ev : eval (app T1 T2) (app T11 T2) @
Ev1 : eval T1 T11 *
Ty : typeOf [] T1 (arrowTy Ty1 Ty)
Ty1 : typeOf [] T2 Ty1
============================
 typeOf [] (app T11 T2) Ty 

The case analysis gives us typing judgments for both T1 and T2. Because we prefixed the case analysis with the name Ty, the new typing judgments are given names starting with Ty. We can now use the apply tactic to use the inductive hypothesis to get a typing judgment for the result of evaluating the first sub-term:

 < apply IH to Ty Ev1.
Subgoal 1:

Variables: Ty T2 T11 T1 Ty1
IH : forall T Ty T', typeOf [] T Ty -> eval T T' * -> typeOf [] T' Ty
Ev : eval (app T1 T2) (app T11 T2) @
Ev1 : eval T1 T11 *
Ty : typeOf [] T1 (arrowTy Ty1 Ty)
Ty1 : typeOf [] T2 Ty1
H1 : typeOf [] T11 (arrowTy Ty1 Ty)
============================
 typeOf [] (app T11 T2) Ty 

The T-App rule now applies to H1 and Ty1. Extensibella will automatically apply this rule when we use the search tactic, finishing this case and moving to the next one:

 < search.
Subgoal 2:

Variables: Ty T21 T1 T2
IH : forall T Ty T', typeOf [] T Ty -> eval T T' * -> typeOf [] T' Ty
Ty : typeOf [] (app T1 T2) Ty
Ev : eval (app T1 T2) (app T1 T21) @
Ev1 : value T1
Ev2 : eval T2 T21 *
============================
 typeOf [] (app T1 T21) Ty 

The next case, for rule E-App-Step2, is similar to the first case and can be completed with the following three commands (note if you are following along that each must be entered individually on the Extensibella command line):

Ty: case Ty.
apply IH to Ty1 Ev2.
search.

This brings us to the last case in the host language, that for the E-App-Subst rule:

Subgoal 3:

Variables: Ty T' T2 Body Ty1 X
IH : forall T Ty T', typeOf [] T Ty -> eval T T' * -> typeOf [] T' Ty
Ty : typeOf [] (app (abs X Ty1 Body) T2) Ty
Ev : eval (app (abs X Ty1 Body) T2) T' @
Ev1 : value T2
Ev2 : subst X T2 Body T'
============================
 typeOf [] T' Ty 

We want to use the subst_type_preservation theorem we would have proven earlier. To do so, we will need a derivation of typing for Body. First, we analyze the derivation of typing again:

 < Ty: case Ty.
Subgoal 3:

Variables: Ty T' T2 Body Ty1 X Ty2
IH : forall T Ty T', typeOf [] T Ty -> eval T T' * -> typeOf [] T' Ty
Ev : eval (app (abs X Ty1 Body) T2) T' @
Ev1 : value T2
Ev2 : subst X T2 Body T'
Ty : typeOf [] (abs X Ty1 Body) (arrowTy Ty2 Ty)
Ty1 : typeOf [] T2 Ty2
============================
 typeOf [] T' Ty 

This does not give us a derivation of typing for Body directly, but it gives us a derivation of typing for the full abstraction. Analyzing this again gives us the typing derivation we need:

 < Ty: case Ty.
Subgoal 3:

Variables: Ty T' T2 Body X Ty2
IH : forall T Ty T', typeOf [] T Ty -> eval T T' * -> typeOf [] T' Ty
Ev : eval (app (abs X Ty2 Body) T2) T' @
Ev1 : value T2
Ev2 : subst X T2 Body T'
Ty1 : typeOf [] T2 Ty2
Ty : typeOf [(X, Ty2)] Body Ty
============================
 typeOf [] T' Ty 

We can now use the apply tactic to apply the subst_type_preservation lemma:

 < apply subst_type_preservation to Ty Ev2 Ty1.
Subgoal 3:

Variables: Ty T' T2 Body X Ty2
IH : forall T Ty T', typeOf [] T Ty -> eval T T' * -> typeOf [] T' Ty
Ev : eval (app (abs X Ty2 Body) T2) T' @
Ev1 : value T2
Ev2 : subst X T2 Body T'
Ty1 : typeOf [] T2 Ty2
Ty : typeOf [(X, Ty2)] Body Ty
H1 : typeOf [] T' Ty
============================
 typeOf [] T' Ty 

This gives us the exact same formula as our goal as an assumption. The search tactic will find this and solve the goal, and, as it is the last goal, finish the full proof as well.

 < search.
Proof completed. 

Importance of Declaration Order

Note in the final case in the host language proof for type preservation we use the previous property, subst_type_preservation, as a lemma. This is the purpose of all the earlier properties; they all acted as lemmas to prove later ones. Our modular metatheory framework ensures modular proofs guarantee not only individual properties are true for composed languages, but also that modular proofs for a set of properties, with some possibly using others as lemmas, guarantee the full set will hold for any composed language.

The validity of full sets of properties is guaranteed by maintaining the order in which the properties are proven by the host language. The host language declares its properties in order, with the proofs of later properties able to use earlier properties as lemmas. Extensions then add their proofs in this order, ensuring all the modular proofs can be composed into full proofs for any composed language.

Projection Constraints

The antepenultimate declaration in the file is for a projection constraint, which is a special kind of extensible property. Projection constraints specify how the semantics of extension-introduced constructs must relate to their projections, their projections being defined by special rules in Sterling. For example, the projection constraint our host language introduces requires a term and its projection have the same type.

The key relation for a projection constraint is its first premise, which must be a projection of some term. Note that we have no proof for the projection constraint in the host language. Because its key relation is a projection and the host language does not introduce projecting syntax, there are no proof cases for the host language to prove.

Note that this projection constraint does not contribute to the proof of type preservation, which was the host language's main goal. Projection constraints can be viewed as a service to extension writers, as they don't generally help the host language prove its own properties, but they make it easier for extensions to prove their new properties.

Extension Induction

The final three declarations are for Ext_Size, Proj_Rel, and Ext_Ind for the eval relation. The name Ext_Ind stands for extension induction. When an extension wants to prove a property using a relation introduced by the host language as its key relation, there is a possibility other extensions that will be included in a composed language will introduce new rules defining that relation. The extension will need to prove a generic case to handle these. The generic case is given by the Ext_Ind declaration for the relation. Having a declaration of this is required for an extension to use a host relation as its key relation, that is, to use it for induction, hence the name.

The generic case the extension proves for its property is when the key relation is derived using the stand-in rule given above, X-Q:

Extensibella_Stand_In {
  Ctx |{tm}- T ~~> T_T
  eval T_T T2
  -------------------- [E-Q]
  eval T T1
}

This declaration also creates an obligation that must be proven by the host language and each extension, that this rule is a valid way of looking at the rules introduced by extensions, embodied in the projection version of the eval relation declared by the Proj_Rel declaration. The Ext_Size declaration introduces a new version of the eval relation that will be useful for proving this. The details of this are discussed more in the context of the let extension below. We leave the proof for the Ext_Ind in the host language as an exercise, recommending returning to it after reading the discussion of it for the let extension.

Moving to Extensions

Because extensions are obligated to prove the host language's properties and maintain their order, we need to compile the host language's proof file before we can start proving properties for our extensions:

$ extensibella --compile host.xthm
The compilation process has Extensibella pull out the theorems in the proof file, give them order tags, and store them in a place it knows. When Extensibella goes to reason about an extension, it then reads this information so it knows the proof obligations the extension has for the properties from the host language, and the order in which they should occur. If an extension module builds on multiple modules, the order tags are used to combine the property orders from each into a shared order containing all the properties and relative orderings from both. Having such an ordering, Extensibella can then check the extension fulfills all its obligations, and that it maintains the orders from the modules on which it builds.

In general, when compiling a proof file, it is a good idea to combine the compilation and proof checking flags:

$ extensibella --check --compile host.xthm
With only the compilation flag, Extensibella assumes each property's proof is present and valid; when we add the proof checking flag, it verifies this before compiling it. This prevents mistakes from sneaking into the compiled form and affecting extensions. Checking is not a default part of compilation because it is much slower than the compilation alone, and is not needed if the file is already known to be valid.

Let Extension

Our first extension adds a new form for terms, a let-binding, and defines the relations introduced by the host language for the new form. It also defines its projection in the Proj-Let rule, projecting to an application of an abstraction.

[Reduce File]
Module walkthrough:let

Builds on walkthrough:host

tm ::= ...
     | let(string, tm, tm)


typeOf Ctx T1 Ty
----------------------------------------------------- [Proj-Let]
Ctx |{tm}- let(X, T1, T2) ~~> app(abs(X, Ty, T2), T1)



eval T1 T11
----------------------------------- [E-Let-Step]
eval let(X, T1, T2) let(X, T11, T2)


value T1
subst X T1 T2 V
--------------------- [E-Let-Subst]
eval let(X, T1, T2) V



X != Y
subst X R T1 S1
subst X R T2 S2
--------------------------------------- [S-Let-NEq]
subst X R let(Y, T1, T2) let(Y, S1, S2)


subst X R T1 S1
--------------------------------------- [S-Let-Eq]
subst X R let(X, T1, T2) let(X, S1, T2)



typeOf Ctx T1 Ty1
typeOf (X, Ty1)::Ctx T2 Ty2
----------------------------- [T-Let]
typeOf Ctx let(X, T1, T2) Ty2

We can compile this module in the same manner as the host module so we can use it with Extensibella:

$ sterling --extensibella walkthrough:let

Proving Host Properties for the Let Extension

The Extensibella proofs for the let extension's properties can be found in the let/let.xthm file, reproduced here:

let.xthm [Reduce File]
Module walkthrough:let.

Prove walkthrough:host:typeOf_unique. [Show Proof]



Prove walkthrough:host:ty_lookup. [Show Proof]



Prove walkthrough:host:subst_type_preservation. [Show Proof]



Prove walkthrough:host:type_preservation. [Show Proof]



Prove_Constraint walkthrough:host:proj_type_same. [Show Proof]



Add_Ext_Size walkthrough:host:eval.
Add_Proj_Rel walkthrough:host:eval.


Prove_Ext_Ind walkthrough:host:eval. [Show Proof]

The proofs the let extension writes are all for new cases of extensible host properties of the various kinds. Thus the top-level declarations are all the Prove and Add versions of the host language's declarations. When Extensibella reads the module declaration, it finds the walkthrough:let module builds on the walkthrough:host module. It then reads the compiled set of properties from the host language, along with their order, so it knows what the let extension needs to prove here, and in what order it must be proven. Extensibella checks this order is maintained by the let extension.

Note we do not have a command for the empty_ty_any theorem from the host language here. Because it is non-extensible, the let extension does not need to add to its proof. If a proof needed it as a lemma, it could still be used, but only after the ty_lookup extensible theorem. This is because the empty_ty_any theorem is part of the order from the host language and the validity of the proofs for a composed language is dependent on maintaining this order.

We will look at the proofs given by the let extension for type preservation, the projection constraint, and Ext_Ind for typing. The earlier properties can be skipped past as we saw in the host language, returning to them later as exercises.

Proving Type Preservation

When the extension is ready to prove the type preservation property, it declares so with a Prove declaration using the property's fully-qualified name that includes the module where it was declared:

 < Prove walkthrough:host:type_preservation.
Subgoal 7:

Variables: Ty T2 T11 X T1
IH : forall T Ty T', typeOf [] T Ty -> eval T T' * -> typeOf [] T' Ty
Ty : typeOf [] (let X T1 T2) Ty
Ev : eval (let X T1 T2) (let X T11 T2) @
Ev1 : eval T1 T11 *
============================
 typeOf [] (let X T11 T2) Ty 

This drops us into the first case for when Ev is derived using a rule introduced by this extension, specifically the E-Let-Step rule. This can be solved by a sequence of tactics similar to those for the E-App-Step1 and E-App-Step2 rules in the host language:

Ty: case Ty.
apply IH to Ty Ev1.
search. 

This brings us to the case for the E-Let-Subst rule:

Subgoal 8:

Variables: Ty T' T2 T1 X
IH : forall T Ty T', typeOf [] T Ty -> eval T T' * -> typeOf [] T' Ty
Ty : typeOf [] (let X T1 T2) Ty
Ev : eval (let X T1 T2) T' @
Ev1 : value T1
Ev2 : subst X T1 T2 T'
============================
 typeOf [] T' Ty 

This is similar to the case for the E-App-Subst rule from the host language and can be solved by a similar chain of tactics:

Ty: case Ty.
apply subst_type_preservation to Ty1 Ev2 Ty.
search. 

Proving Projection Constraint

After proving type preservation, we are ready to prove the projection constraint, and declare so with a Prove_Constraint declaration:

 < Prove_Constraint walkthrough:host:proj_type_same.

Variables: G Ty T1 T2 Ty1 X
Hyp : G |{tm}- let X T1 T2 ~~> app (abs X Ty1 T2) T1
Hyp1 : typeOf G (let X T1 T2) Ty
Hyp2 : typeOf G T1 Ty1
============================
 typeOf G (app (abs X Ty1 T2) T1) Ty

This gives us the case for the projection being derived using the Proj-Let rule. To show this, we need to show the projection app (abs X Ty1 T2) T1 has the same type as the original term let X T1 T2. We can analyze the typing derivation for the original term, since its primary component is built by the let constructor:

 < case Hyp1.

Variables: G Ty T1 T2 Ty1 X Ty2
Hyp : G |{tm}- let X T1 T2 ~~> app (abs X Ty1 T2) T1
Hyp2 : typeOf G T1 Ty1
H1 : typeOf G T1 Ty2
H2 : typeOf ((X, Ty2)::G) T2 Ty
============================
 typeOf G (app (abs X Ty1 T2) T1) Ty

We need to know that T2 has type Ty if X is assigned type Ty1 in its context. To do this, we can use the type uniqueness property introduced by the host language to show Ty1 and Ty2 must actually be the same:

 < apply typeOf_unique to Hyp2 H1.

Variables: G Ty T1 T2 X Ty2
Hyp : G |{tm}- let X T1 T2 ~~> app (abs X Ty2 T2) T1
Hyp2 : typeOf G T1 Ty2
H1 : typeOf G T1 Ty2
H2 : typeOf ((X, Ty2)::G) T2 Ty
============================
 typeOf G (app (abs X Ty2 T2) T1) Ty

This unified Ty1 and Ty2, so we have the premises to use the T-App and T-Abs rules to prove the conclusion:

 < search.
Proof completed.

Adding Ext_Size and Proj_Rel and Proving Ext_Ind

For Ext_Ind, each extension has an obligation to show the rules it introduces are compatible with the stand-in rule defined by the host language. For the eval relation, this is

Extensibella_Stand_In {
  Ctx |{tm}- T ~~> T_T
  eval T_T T2
  -------------------- [E-Q]
  eval T T1
}
This compatibility for a relation rel is defined by a relation <rel {P}>, called the projection version of rel. This relation is declared by the Proj_Rel and Add_Proj_Rel commands. In our case, this relation is <eval {P}>. Each rule for this relation corresponds to one for the underlying relation, with those introduced by extensions having the stand-in rule incorporated. For example, the rule for the projection version of eval corresponding to E-Let-Step is
<eval {P}> T1 T11
Ctx |{tm}- let(X, T1, T2) ~~> T_T
<eval {P}> T_T T3
----------------------------------------- [E-Let-Step {P}]
<eval {P}> let(X, T1, T2) let(X, T11, T2)
This rule incorporates both the standard premises of the E-Let-Step rule and the premises of the stand-in rule instantiated for the conclusion of E-Let-Step.

In order to prove the projection version of the eval relation follows from the relation itself, we need a way to show we will have <eval {P}> hold for the projection of the primary component of any extension-introduced rule even though we do not have a derivation of the basic eval relation for it. The extension size version of the eval relation, written <eval {ES}>, will give us a way to do this. The extension size version of a relation incorporates a count of the number of extension-introduced rules in a derivation. Both of these versions of relations, and how the extension size version of a relation gives us a hook for showing the projection version will hold on the projection, can be read about in our paper.

What Ext_Ind shows is that we have a derivation of the projection version of a relation whenever we have a derivation of the relation itself, as well as a derivation of typing for the original term. Because projection can rely on typing, this extra premise is useful in the proof. When we have declared the extension size version of the relation using Ext_Size, as we have for eval, Extensibella has us start from a derivation of the extension size version of the relation rather than the relation itself. Thus what we need to prove here is

forall G T T' Ty n, <eval {ES}> T T' n -> typeOf G T Ty -> <eval {P}> T T'
where n is the extension size of the original derivation, that is, the number of extension-introduced rules used in the derivation. We will prove this by induction on the extension size n and the derivation of <eval {ES}> T T' n. The induction on n also requires a second premise, acc n. The acc predicate essentially encodes strong induction on natural numbers by holding for a number only if it holds for all non-negative integers less than it.

We start by declaring we are ready to fulfill the proof obligation for the Ext_Ind for the typeOf relation:

 < Prove_Ext_Ind walkthrough:host:eval.
Subgoal 4:

Variables: N G Ty N2 T2 T11 X T1
IH : forall N G T T' Ty,
       <eval {ES}> T T' N -> acc N * -> typeOf G T Ty -> <eval {P}> T T'
IH1 : forall N G T T' Ty,
        <eval {ES}> T T' N ** -> acc N @ -> typeOf G T Ty -> <eval {P}> T T'
R : <eval {ES}> (let X T1 T2) (let X T11 T2) N @@
Acc : acc N @
Ty : typeOf G (let X T1 T2) Ty
R1 : 1 + N2 = N
R2 : <eval {ES}> T1 T11 N2 **
============================
 <eval {P}> (let X T1 T2) (let X T11 T2)

This puts us into the proof case for when <eval {ES}> is derived using the rule corresponding to the T-Let-Step rule. We then analyze acc n to unfold its definition:

 < Acc: case Acc.
Subgoal 4:

Variables: N G Ty N2 T2 T11 X T1
IH : forall N G T T' Ty,
       <eval {ES}> T T' N -> acc N * -> typeOf G T Ty -> <eval {P}> T T'
IH1 : forall N G T T' Ty,
        <eval {ES}> T T' N ** -> acc N @ -> typeOf G T Ty -> <eval {P}> T T'
R : <eval {ES}> (let X T1 T2) (let X T11 T2) N @@
Ty : typeOf G (let X T1 T2) Ty
R1 : 1 + N2 = N
R2 : <eval {ES}> T1 T11 N2 **
Acc : forall M, 0 <= M -> M < N -> acc M *
============================
 <eval {P}> (let X T1 T2) (let X T11 T2)

This gives us a way to build a derivation of acc suitable for use with the inductive hypothesis, as seen by the * annotation on its unfolded conclusion. We can use the unfold tactic to see the definition of <eval {P}> (let X T1 T2) (let X T11 T2), and thus what we need to prove:

 < unfold.
Subgoal 4:

Variables: N G Ty N2 T2 T11 X T1
IH : forall N G T T' Ty,
       <eval {ES}> T T' N -> acc N * -> typeOf G T Ty -> <eval {P}> T T'
IH1 : forall N G T T' Ty,
        <eval {ES}> T T' N ** -> acc N @ -> typeOf G T Ty -> <eval {P}> T T'
R : <eval {ES}> (let X T1 T2) (let X T11 T2) N @@
Ty : typeOf G (let X T1 T2) Ty
R1 : 1 + N2 = N
R2 : <eval {ES}> T1 T11 N2 **
Acc : forall M, 0 <= M -> M < N -> acc M *
============================
 exists Ctx T_T T3,
   <eval {P}> T1 T11 /\ (Ctx |{tm}- let X T1 T2 ~~> T_T /\ <eval {P}> T_T T3)

We see the first conjunct in the conclusion are those for the premises of the E-Let-Step evaluation rule and the others are for the stand-in rule, but now using the projection version of the relation. Then we need to show the original let projects, that its projection evaluates, and that each of the premises can be turned into its projection version.

We start with showing the projection exists. This requires a typing derivation for T1, which we can get by breaking down the typing derivation:

 < Ty: case Ty.
Subgoal 4:

Variables: N G Ty N2 T2 T11 X T1 Ty1
IH : forall N G T T' Ty,
       <eval {ES}> T T' N -> acc N * -> typeOf G T Ty -> <eval {P}> T T'
IH1 : forall N G T T' Ty,
        <eval {ES}> T T' N ** -> acc N @ -> typeOf G T Ty -> <eval {P}> T T'
R : <eval {ES}> (let X T1 T2) (let X T11 T2) N @@
R1 : 1 + N2 = N
R2 : <eval {ES}> T1 T11 N2 **
Acc : forall M, 0 <= M -> M < N -> acc M *
Ty : typeOf G T1 Ty1
Ty1 : typeOf ((X, Ty1)::G) T2 Ty
============================
 exists Ctx T_T T3,
   <eval {P}> T1 T11 /\ (Ctx |{tm}- let X T1 T2 ~~> T_T /\ <eval {P}> T_T T3)

 < assert G |{tm}- let X T1 T2 ~~> app (abs X Ty1 T2) T1.
Subgoal 4:

Variables: N G Ty N2 T2 T11 X T1 Ty1
IH : forall N G T T' Ty,
       <eval {ES}> T T' N -> acc N * -> typeOf G T Ty -> <eval {P}> T T'
IH1 : forall N G T T' Ty,
        <eval {ES}> T T' N ** -> acc N @ -> typeOf G T Ty -> <eval {P}> T T'
R : <eval {ES}> (let X T1 T2) (let X T11 T2) N @@
R1 : 1 + N2 = N
R2 : <eval {ES}> T1 T11 N2 **
Acc : forall M, 0 <= M -> M < N -> acc M *
Ty : typeOf G T1 Ty1
Ty1 : typeOf ((X, Ty1)::G) T2 Ty
H1 : G |{tm}- let X T1 T2 ~~> app (abs X Ty1 T2) T1
============================
 exists Ctx T_T T3,
   <eval {P}> T1 T11 /\ (Ctx |{tm}- let X T1 T2 ~~> T_T /\ <eval {P}> T_T T3)

The other portions of the conclusion are related, as evaluating the projection ultimately requires the same premises as the E-Let-Step rule. These will require using the inductive hypothesis, which will in turn require a derivation of acc for N2. We start by building a derivation of is_integer for N2. We can use the ext_size_is_int_eval property, also introduced by the Ext_Size declaration but which the user does not need to prove, as it can be proven automatically.

 < IsN2: apply ext_size_is_int_typeOf to R2.
Subgoal 4:

Variables: N G Ty N2 T2 T11 X T1 Ty1
IH : forall N G T T' Ty,
       <eval {ES}> T T' N -> acc N * -> typeOf G T Ty -> <eval {P}> T T'
IH1 : forall N G T T' Ty,
        <eval {ES}> T T' N ** -> acc N @ -> typeOf G T Ty -> <eval {P}> T T'
R : <eval {ES}> (let X T1 T2) (let X T11 T2) N @@
R1 : 1 + N2 = N
R2 : <eval {ES}> T1 T11 N2 **
Acc : forall M, 0 <= M -> M < N -> acc M *
Ty : typeOf G T1 Ty1
Ty1 : typeOf ((X, Ty1)::G) T2 Ty
H1 : G |{tm}- let X T1 T2 ~~> app (abs X Ty1 T2) T1
IsN2 : is_integer N2
============================
 exists Ctx T_T T3,
   <eval {P}> T1 T11 /\ (Ctx |{tm}- let X T1 T2 ~~> T_T /\ <eval {P}> T_T T3)

We can now use an Extensibella standard library property to show N2 < N:

 < L: apply lt_plus_one to R1 _.
Subgoal 4:

Variables: N G Ty N2 T2 T11 X T1 Ty1
IH : forall N G T T' Ty,
       <eval {ES}> T T' N -> acc N * -> typeOf G T Ty -> <eval {P}> T T'
IH1 : forall N G T T' Ty,
        <eval {ES}> T T' N ** -> acc N @ -> typeOf G T Ty -> <eval {P}> T T'
R : <eval {ES}> (let X T1 T2) (let X T11 T2) N @@
R1 : 1 + N2 = N
R2 : <eval {ES}> T1 T11 N2 **
Acc : forall M, 0 <= M -> M < N -> acc M *
Ty : typeOf G T1 Ty1
Ty1 : typeOf ((X, Ty1)::G) T2 Ty
H1 : G |{tm}- let X T1 T2 ~~> app (abs X Ty1 T2) T1
IsN2 : is_integer N2
L : N2 < N
============================
 exists Ctx T_T T3,
   <eval {P}> T1 T11 /\ (Ctx |{tm}- let X T1 T2 ~~> T_T /\ <eval {P}> T_T T3)

To show N2 is at least zero, a requirement for acc, we can use another property declared and automatically proven by Ext_Size:

 < PosN2: apply ext_size_pos_typeOf to R2.
Subgoal 4:

Variables: N G Ty N2 T2 T11 X T1 Ty1
IH : forall N G T T' Ty,
       <eval {ES}> T T' N -> acc N * -> typeOf G T Ty -> <eval {P}> T T'
IH1 : forall N G T T' Ty,
        <eval {ES}> T T' N ** -> acc N @ -> typeOf G T Ty -> <eval {P}> T T'
R : <eval {ES}> (let X T1 T2) (let X T11 T2) N @@
R1 : 1 + N2 = N
R2 : <eval {ES}> T1 T11 N2 **
Acc : forall M, 0 <= M -> M < N -> acc M *
Ty : typeOf G T1 Ty1
Ty1 : typeOf ((X, Ty1)::G) T2 Ty
H1 : G |{tm}- let X T1 T2 ~~> app (abs X Ty1 T2) T1
IsN2 : is_integer N2
L : N2 < N
PosN2 : 0 <= N2
============================
 exists Ctx T_T T3,
   <eval {P}> T1 T11 /\ (Ctx |{tm}- let X T1 T2 ~~> T_T /\ <eval {P}> T_T T3)

We can now build a derivation of acc N2:

 < A: apply Acc to PosN2 L.
Subgoal 4:

Variables: N G Ty N2 T2 T11 X T1 Ty1
IH : forall N G T T' Ty,
       <eval {ES}> T T' N -> acc N * -> typeOf G T Ty -> <eval {P}> T T'
IH1 : forall N G T T' Ty,
        <eval {ES}> T T' N ** -> acc N @ -> typeOf G T Ty -> <eval {P}> T T'
R : <eval {ES}> (let X T1 T2) (let X T11 T2) N @@
R1 : 1 + N2 = N
R2 : <eval {ES}> T1 T11 N2 **
Acc : forall M, 0 <= M -> M < N -> acc M *
Ty : typeOf G T1 Ty1
Ty1 : typeOf ((X, Ty1)::G) T2 Ty
H1 : G |{tm}- let X T1 T2 ~~> app (abs X Ty1 T2) T1
IsN2 : is_integer N2
L : N2 < N
PosN2 : 0 <= N2
A : acc N2 *
============================
 exists Ctx T_T T3,
   <eval {P}> T1 T11 /\ (Ctx |{tm}- let X T1 T2 ~~> T_T /\ <eval {P}> T_T T3)

Using this, we can use the induction hypothesis to get a derivation of <eval {P}> for T1:

 < apply IH to R2 A Ty.
Subgoal 4:

Variables: N G Ty N2 T2 T11 X T1 Ty1
IH : forall N G T T' Ty,
       <eval {ES}> T T' N -> acc N * -> typeOf G T Ty -> <eval {P}> T T'
IH1 : forall N G T T' Ty,
        <eval {ES}> T T' N ** -> acc N @ -> typeOf G T Ty -> <eval {P}> T T'
R : <eval {ES}> (let X T1 T2) (let X T11 T2) N @@
R1 : 1 + N2 = N
R2 : <eval {ES}> T1 T11 N2 **
Acc : forall M, 0 <= M -> M < N -> acc M *
Ty : typeOf G T1 Ty1
Ty1 : typeOf ((X, Ty1)::G) T2 Ty
H1 : G |{tm}- let X T1 T2 ~~> app (abs X Ty1 T2) T1
IsN2 : is_integer N2
L : N2 < N
PosN2 : 0 <= N2
A : acc N2 *
H2 : <eval {P}> T1 T11
============================
 exists Ctx T_T T3,
   <eval {P}> T1 T11 /\ (Ctx |{tm}- let X T1 T2 ~~> T_T /\ <eval {P}> T_T T3)

This new assumption is what we need to complete the derivations, so we can finish the proof case:

 < search.
Subgoal 5:

Variables: G T' Ty T2 T1 X
IH : forall N G T T' Ty,
       <eval {ES}> T T' N -> acc N * -> typeOf G T Ty -> <eval {P}> T T'
IH1 : forall N G T T' Ty,
        <eval {ES}> T T' N ** -> acc N @ -> typeOf G T Ty -> <eval {P}> T T'
R : <eval {ES}> (let X T1 T2) T' 1 @@
Acc : acc 1 @
Ty : typeOf G (let X T1 T2) Ty
R1 : value T1
R2 : subst X T1 T2 T'
============================
 <eval {P}> (let X T1 T2) T'

This leaves us with the case for the E-Let-Subst case. Because this rule does not have any evaluation premises, only value and subst, its proof is similar but simpler:

 < unfold.
Subgoal 5:

Variables: G T' Ty T2 T1 X
IH : forall N G T T' Ty,
       <eval {ES}> T T' N -> acc N * -> typeOf G T Ty -> <eval {P}> T T'
IH1 : forall N G T T' Ty,
        <eval {ES}> T T' N ** -> acc N @ -> typeOf G T Ty -> <eval {P}> T T'
R : <eval {ES}> (let X T1 T2) T' 1 @@
Acc : acc 1 @
Ty : typeOf G (let X T1 T2) Ty
R1 : value T1
R2 : subst X T1 T2 T'
============================
 exists Ctx T_T T3,
   (value T1 /\ subst X T1 T2 T') /\
   (Ctx |{tm}- let X T1 T2 ~~> T_T /\ <eval {P}> T_T T3)

 < Ty: case Ty.
Subgoal 5:

Variables: G T' Ty T2 T1 X Ty1
IH : forall N G T T' Ty,
       <eval {ES}> T T' N -> acc N * -> typeOf G T Ty -> <eval {P}> T T'
IH1 : forall N G T T' Ty,
        <eval {ES}> T T' N ** -> acc N @ -> typeOf G T Ty -> <eval {P}> T T'
R : <eval {ES}> (let X T1 T2) T' 1 @@
Acc : acc 1 @
R1 : value T1
R2 : subst X T1 T2 T'
Ty : typeOf G T1 Ty1
Ty1 : typeOf ((X, Ty1)::G) T2 Ty
============================
 exists Ctx T_T T3,
   (value T1 /\ subst X T1 T2 T') /\
   (Ctx |{tm}- let X T1 T2 ~~> T_T /\ <eval {P}> T_T T3)

 < assert G |{tm}- let X T1 T2 ~~> app (abs X Ty1 T2) T1.
Subgoal 5:

Variables: G T' Ty T2 T1 X Ty1
IH : forall N G T T' Ty,
       <eval {ES}> T T' N -> acc N * -> typeOf G T Ty -> <eval {P}> T T'
IH1 : forall N G T T' Ty,
        <eval {ES}> T T' N ** -> acc N @ -> typeOf G T Ty -> <eval {P}> T T'
R : <eval {ES}> (let X T1 T2) T' 1 @@
Acc : acc 1 @
R1 : value T1
R2 : subst X T1 T2 T'
Ty : typeOf G T1 Ty1
Ty1 : typeOf ((X, Ty1)::G) T2 Ty
H1 : G |{tm}- let X T1 T2 ~~> app (abs X Ty1 T2) T1
============================
 exists Ctx T_T T3,
   (value T1 /\ subst X T1 T2 T') /\
   (Ctx |{tm}- let X T1 T2 ~~> T_T /\ <eval {P}> T_T T3)

 < search.
Proof completed.

Big Step Extension

Our other extension does not introduce any new syntax, only defining a new relation for big-step evaluation.

[Reduce File]
Module walkthrough:big_step

Builds on walkthrough:host


Judgment big_step : tm* tm

value T
------------ [Big-End]
big_step T T


eval T T1
big_step T1 T2
-------------- [Big-Step]
big_step T T2


[] |{tm}- T ~~> T_T
big_step T_T T1
------------------- [Big-D]*
big_step T T1

The big-step evaluation defined here is a bit odd, but we make it so to make our example property easier to understand, making the focus on the aspects of proving an extension-introduced property rather than the specific property. The oddness here is that we may step through multiple small-step evaluation steps (eval steps) or we may project away any extension syntax and step through the evaluation of its projection.

We can compile this for Extensibella as we did for the others:

$ sterling --extensibella walkthrough:big_step

Proving Properties for the Big Step Extension

The Extensibella proofs for the big step extension can be found in the big_step/big_step.xthm file, reproduced here:

big_step.xthm [Reduce File]
Module walkthrough:big_step.


Prove walkthrough:host:typeOf_unique.


Prove walkthrough:host:ty_lookup.


Prove walkthrough:host:subst_type_preservation.


Prove walkthrough:host:type_preservation.


Prove_Constraint walkthrough:host:proj_type_same.


Add_Ext_Size walkthrough:host:eval.
Add_Proj_Rel walkthrough:host:eval.


Prove_Ext_Ind walkthrough:host:eval.


Extensible_Theorem
  big_step_type_preservation : forall T Ty T',
    Ty : typeOf [] T Ty ->
    Big : big_step T T' ->
    typeOf [] T' Ty
  on Big. [Show Proof]

As we saw with the let extension, Extensibella knows the walkthrough:big_step module builds on the host language and thus expects the Prove version of each extensible theorem from the host language. Unlike in the let extension, the big step extension does not introduce any new syntax or new rules for the key relations of these theorems, and thus has nothing new to prove for them. However, Extensibella still requires the Prove declarations for two reasons. First, it does not check whether there are new rules until the Prove declaration. Second, declaring the imported theorems makes it clear where new theorems, such as big_step_type_preservation, belong in the order and what existing theorems they may use as lemmas and, in more complex examples, what host properties may use them as lemmas in the new proofs. We see this use of existing properties as lemmas in proving a new theorem in the proof of big_step_type_preservation, as we use both the type_preservation theorem and proj_type_same projection constraint from the host language as lemmas.

The new big_step_type_preservation theorem in this extension is also declared using the Extensible_Theorem keyword, just like the host language's theorems, with its key relation being the new big_step relation it introduces.

 < Extensible_Theorem
     big_step_type_preservation : forall T Ty T',
       Ty : typeOf [] T Ty ->
       Big : big_step T T' ->
       typeOf [] T' Ty
     on Big.
Subgoal 1:

Variables: Ty T'
IH : forall T Ty T', typeOf [] T Ty -> big_step T T' * -> typeOf [] T' Ty
Ty : typeOf [] T' Ty
Big : big_step T' T' @
Big1 : value T'
============================
 typeOf [] T' Ty

Unlike the properties from the host language, there are two extension points here. One is that new extensions may build on this one and add new rules for it. This is the same as we saw for the properties from the host language. The other extension point here is that other extensions may introduce new constructs not known here, but for which the big_step relation will hold. We see this with the let extension; the big step extension does not know the let construct exists, but the big_step relation will still hold for it in a composed language including both extensions.

This property has three cases, two for the known rules Big-End and Big-Step, with the third being a generic case that can be used for any constructs from other extensions, such as let. The first one, into which we drop immediately, is that for when the big-step evaluation was derived using the Big-End rule. As there is no evaluation here, the proof is immediate:

 < search.
Subgoal 2:

Variables: T Ty T' T3
IH : forall T Ty T', typeOf [] T Ty -> big_step T T' * -> typeOf [] T' Ty
Ty : typeOf [] T Ty
Big : big_step T T' @
Big1 : eval T T3
Big2 : big_step T3 T' *
============================
 typeOf [] T' Ty

The next case is that for when the big-step evaluation was derived using the Big-Step rule. Here we can apply the type preservation property of the host language to find T3 has the same type, then the inductive hypothesis to find T' has the same type:

< apply type_preservation to Ty Big1.
Subgoal 2:

Variables: T Ty T' T3
IH : forall T Ty T', typeOf [] T Ty -> big_step T T' * -> typeOf [] T' Ty
Ty : typeOf [] T Ty
Big : big_step T T' @
Big1 : eval T T3
Big2 : big_step T3 T' *
H1 : typeOf [] T3 Ty
============================
 typeOf [] T' Ty

< apply IH to _ Big2.
Subgoal 2:

Variables: T Ty T' T3
IH : forall T Ty T', typeOf [] T Ty -> big_step T T' * -> typeOf [] T' Ty
Ty : typeOf [] T Ty
Big : big_step T T' @
Big1 : eval T T3
Big2 : big_step T3 T' *
H1 : typeOf [] T3 Ty
H2 : typeOf [] T' Ty
============================
 typeOf [] T' Ty

< search.
Subgoal 3:

Variables: Ty T' T_T
IH : forall T Ty T', typeOf [] T Ty -> big_step T T' * -> typeOf [] T' Ty
Ty : typeOf [] <unknown I tm> Ty
Big : big_step <unknown I tm> T' @
Big1 : [] |{tm}- <unknown I tm> ~~> T_T
Big2 : big_step T_T T' *
============================
 typeOf [] T' Ty

The final case, which we see as the next goal after the search tactic completing the case for Big-Step, is the generic case. Because our key relation is introduced by this extension, the generic case uses the default rule introduced by the module, Big-D, which is instantiated for each construct introduced by another extension in a composition. For the generic proof, it is instantiated for a special term <unknown I tm> representing this class of terms unknown in the context of the current module.

Because this generic term is a stand-in for terms introduced by other modules that will introduce their own semantics, we do not know how existing relations, such as typeOf, are defined for it and case analysis is disallowed. If we try, we get an error message:

 < case Ty.
Error:  Cannot do case analysis on host extensible relation with unknown primary component
Subgoal 3:

Variables: Ty T' T_T
IH : forall T Ty T', typeOf [] T Ty -> big_step T T' * -> typeOf [] T' Ty
Ty : typeOf [] <unknown I tm> Ty
Big : big_step <unknown I tm> T' @
Big1 : [] |{tm}- <unknown I tm> ~~> T_T
Big2 : big_step T_T T' *
============================
 typeOf [] T' Ty

Because case analysis is limited here, we instead rely on projection constraints and other existing properties to show what we want about the semantics of <unknown I tm>. We can start our proof of this case by using the projection constraint from the host language to show the projection T_T has the same type:

 < apply proj_type_same to Big1 Ty.
Subgoal 3:

Variables: Ty T' T_T
IH : forall T Ty T', typeOf [] T Ty -> big_step T T' * -> typeOf [] T' Ty
Ty : typeOf [] <unknown I tm> Ty
Big : big_step <unknown I tm> T' @
Big1 : [] |{tm}- <unknown I tm> ~~> T_T
Big2 : big_step T_T T' *
H1 : typeOf [] T_T Ty
============================
 typeOf [] T' Ty

This gives us the typing derivation we need for applying the inductive hypothesis, which we can do to complete the proof:

 < apply IH to _ Big2.
Subgoal 3:

Variables: Ty T' T_T
IH : forall T Ty T', typeOf [] T Ty -> big_step T T' * -> typeOf [] T' Ty
Ty : typeOf [] <unknown I tm> Ty
Big : big_step <unknown I tm> T' @
Big1 : [] |{tm}- <unknown I tm> ~~> T_T
Big2 : big_step T_T T' *
H1 : typeOf [] T_T Ty
H2 : typeOf [] T' Ty
============================
 typeOf [] T' Ty

 < search.
Proof completed.

If an extension-introduced property is proven using a relation from the host language as its key relation, instead of an extension-introduced relation as we used here, the ideas behind the proof will be similar. However, instead of the default rule given by the module instantiated for the generic term <unknown I tm> as the rule giving rise to the case, it will have the stand-in rule given by the host language instantiated for a generic constructor <unknown K tm> as the rule giving rise to the case.

Proof Composition

Once each extension has completed its proofs, we know any composed language will have all properties introduced by all modules included in the composition. We can check this for a composition by using Extensibella to build a composed Abella proof for all the properties.

To build a composition, we need a Sterling module that composes all the pieces. Make a directory named composed as a sibling of the host, let, and big_step directories, and put the following in a file named composed.sos in it:

composed.sos
Module walkthrough:composed

Builds on walkthrough:host
Builds on walkthrough:let
Builds on walkthrough:big_step

We will need to compile this twice, once for a regular Extensibella proof, the same way we have compiled the others, and once for the Extensibella composition, as these have slightly different requirements.

$ sterling --extensibella walkthrough:composed
$ sterling --extensibellaFull walkthrough:composed

We also need to create an Extensibella file for the composed module. This is necessary for Extensibella to know what properties the modules in the composition add, if any. We can have Extensibella generate the file for us. To do this, we need to compile the files for the let and big step extensions so Extensibella knows what properties they add and the order in which they add them:

$ extensibella --compile walkthrough/let/let.xthm
$ extensibella --compile walkthrough/big_step/big_step.xthm
$ extensibella --generate walkthrough:composed walkthrough/composed/composed.xthm
composed.xthm [Reduce File]
Module walkthrough:composed.


Prove walkthrough:host:typeOf_unique.


Prove walkthrough:host:ty_lookup.


Prove walkthrough:host:subst_type_preservation.


Prove walkthrough:host:type_preservation.


Prove_Constraint walkthrough:host:proj_type_same.


Add_Ext_Size walkthrough:host:eval.
Add_Proj_Rel walkthrough:host:eval.


Prove_Ext_Ind walkthrough:host:eval.


Prove walkthrough:big_step:big_step_type_preservation.

When we generate the Extensibella file for the walkthrough:composed module, Extensibella takes the property orders from each module on which it builds and combines them to form an order containing all the properties from all the modules. This composed order maintains the order from each module individually, so each use of a property as a lemma will still be valid in the composition.

We now have all the pieces necessary to have Extensibella build the composition. To do so, we give the name of the file to be output, along with the module for which we are building the composition, and all the proof files for the modules included in the composition:

$ extensibella --compose walkthrough/out.thm walkthrough:composed walkthrough/host/host.xthm walkthrough/let/let.xthm walkthrough/big_step/big_step.xthm walkthrough/composed/composed.xthm path/to/sterling/stdLib/stdLib.xthm
Note we need to include the Extensibella proof file for the Sterling standard library as well, since the standard library is included in all Sterling modules. Extensibella does not treat the Sterling standard library module specially, so its properties, which are all non-extensible, are also included in the Extensibella modules using them and their proofs are needed for the composition.

The produced Abella file, out.thm in our example, contains the Abella specification of the language and Abella proofs of each property from any module in the composition. We show here a version of it edited for white space to fit better in the page.

out.thm [Expand File]
/********************************************************************
 Extensibella Standard Library
 ********************************************************************/
Kind $lib__bool   type.
Kind $lib__nat    type.
Kind $lib__pair   type -> type -> type.
Import "/path/to/extensibella/stdLib/bools".
Import "/path/to/extensibella/stdLib/integers".
Import "/path/to/extensibella/stdLib/integer_addition".
Import "/path/to/extensibella/stdLib/integer_multiplication".
Import "/path/to/extensibella/stdLib/integer_division".
Import "/path/to/extensibella/stdLib/integer_comparison".
Import "/path/to/extensibella/stdLib/lists".
Import "/path/to/extensibella/stdLib/strings".
Import "/path/to/extensibella/stdLib/pairs".
Import "/path/to/extensibella/stdLib/extSize_induction".


/********************************************************************
 Language Definition
 ********************************************************************/
Kind $ty__walkthrough-$-host-$-tm   type.
Kind $ty__walkthrough-$-host-$-ty   type.


Type walkthrough-$-let-$-let   (list $char) -> ($ty__walkthrough-$-host-$-tm) ->
         ($ty__walkthrough-$-host-$-tm) -> $ty__walkthrough-$-host-$-tm.
Type walkthrough-$-host-$-var   (list $char) -> $ty__walkthrough-$-host-$-tm.
Type walkthrough-$-host-$-abs   (list $char) -> ($ty__walkthrough-$-host-$-ty) ->
         ($ty__walkthrough-$-host-$-tm) -> $ty__walkthrough-$-host-$-tm.
Type walkthrough-$-host-$-app   ($ty__walkthrough-$-host-$-tm) ->
         ($ty__walkthrough-$-host-$-tm) -> $ty__walkthrough-$-host-$-tm.
Type walkthrough-$-host-$-arrowTy   ($ty__walkthrough-$-host-$-ty) ->
         ($ty__walkthrough-$-host-$-ty) -> $ty__walkthrough-$-host-$-ty.
Type walkthrough-$-host-$-intTy   $ty__walkthrough-$-host-$-ty.


Define $fix__sterling-$-stdLib-$-range : ($lib__integer) -> ($lib__integer) ->
                                         (list ($lib__integer)) -> prop by
$fix__sterling-$-stdLib-$-range (Low) (High) (nil) := $greater_integer (Low) (High);
$fix__sterling-$-stdLib-$-range (Low) (High) ((Low)::(Rest)) :=
    exists PlusOne, ($lesseq_integer (Low) (High)) /\
                    (($plus_integer ($posInt ($succ ($zero))) (Low) (PlusOne)) /\
                    ($fix__sterling-$-stdLib-$-range (PlusOne) (High) (Rest))).
Define $fix__sterling-$-stdLib-$-take : ($lib__integer) -> (list (Var_A)) ->
                                        (list (Var_A)) -> prop by
$fix__sterling-$-stdLib-$-take ($posInt ($zero)) (L) (nil);
$fix__sterling-$-stdLib-$-take (N) ((X)::(L)) ((X)::(F)) :=
    exists N1, ($plus_integer ($posInt ($succ ($zero))) (N1) (N)) /\
               ($fix__sterling-$-stdLib-$-take (N1) (L) (F)).
Define $fix__sterling-$-stdLib-$-drop : ($lib__integer) -> (list (Var_A)) ->
                                        (list (Var_A)) -> prop by
$fix__sterling-$-stdLib-$-drop ($posInt ($zero)) (L) (L);
$fix__sterling-$-stdLib-$-drop (N) ((X)::(L)) (R) :=
    exists N1, ($plus_integer ($posInt ($succ ($zero))) (N1) (N)) /\
               ($fix__sterling-$-stdLib-$-drop (N1) (L) (R)).
Define $fix__sterling-$-stdLib-$-zip : (list (Var_A)) -> (list (Var_B)) ->
                                       (list ($lib__pair (Var_A) (Var_B))) -> prop by
$fix__sterling-$-stdLib-$-zip (nil) (nil) (nil);
$fix__sterling-$-stdLib-$-zip ((A)::(ARest)) ((B)::(BRest))
                              (($pair_c (A) (B))::(Rest)) :=
    $fix__sterling-$-stdLib-$-zip (ARest) (BRest) (Rest).
Define $fix__sterling-$-stdLib-$-values : (list ($lib__pair (Var_A) (Var_B))) ->
                                          (list (Var_B)) -> prop by
$fix__sterling-$-stdLib-$-values (nil) (nil);
$fix__sterling-$-stdLib-$-values (($pair_c (A) (B))::(Rest)) ((B)::(VRest)) :=
    $fix__sterling-$-stdLib-$-values (Rest) (VRest).
Define $fix__sterling-$-stdLib-$-domain : (list ($lib__pair (Var_A) (Var_B))) ->
                                          (list (Var_A)) -> prop by
$fix__sterling-$-stdLib-$-domain (nil) (nil);
$fix__sterling-$-stdLib-$-domain (($pair_c (A) (B))::(Rest)) ((A)::(DRest)) :=
    $fix__sterling-$-stdLib-$-domain (Rest) (DRest).
Define $fix__sterling-$-stdLib-$-count : (Var_A) -> (list (Var_A)) ->
                                         ($lib__integer) -> prop by
$fix__sterling-$-stdLib-$-count (X) (nil) ($posInt ($zero));
$fix__sterling-$-stdLib-$-count (X) ((X)::(Rest)) (N1) :=
    exists N, ($fix__sterling-$-stdLib-$-count (X) (Rest) (N)) /\
              ($plus_integer ($posInt ($succ ($zero))) (N) (N1));
$fix__sterling-$-stdLib-$-count (X) ((Y)::(Rest)) (N) :=
    (((X) = (Y)) -> (false)) /\ ($fix__sterling-$-stdLib-$-count (X) (Rest) (N)).
Define $fix__sterling-$-stdLib-$-select : (Var_Item) -> (list (Var_Item)) ->
                                          (list (Var_Item)) -> prop by
$fix__sterling-$-stdLib-$-select (Item) (Rest) ((Item)::(Rest));
$fix__sterling-$-stdLib-$-select (Item) ((I)::(L1)) ((I)::(L2)) :=
    $fix__sterling-$-stdLib-$-select (Item) (L1) (L2).
Define $fix__sterling-$-stdLib-$-permutation : (list (Var_A)) -> (list (Var_A)) -> prop by
$fix__sterling-$-stdLib-$-permutation (nil) (nil);
$fix__sterling-$-stdLib-$-permutation ((A)::(Rest)) (L) :=
    exists L2, ($fix__sterling-$-stdLib-$-select (A) (L2) (L)) /\
               ($fix__sterling-$-stdLib-$-permutation (Rest) (L2)).
Define $fix__sterling-$-stdLib-$-mem : (Var_Item) -> (list (Var_Item)) -> prop by
$fix__sterling-$-stdLib-$-mem (Item) ((Item)::(Rest));
$fix__sterling-$-stdLib-$-mem (Item) ((I)::(Rest)) :=
    $fix__sterling-$-stdLib-$-mem (Item) (Rest).
Define $fix__sterling-$-stdLib-$-subset : (list (Var_A)) -> (list (Var_A)) -> prop by
$fix__sterling-$-stdLib-$-subset (nil) (L);
$fix__sterling-$-stdLib-$-subset ((X)::(Rest)) (Supset) :=
    ($fix__sterling-$-stdLib-$-mem (X) (Supset)) /\
    ($fix__sterling-$-stdLib-$-subset (Rest) (Supset)).
Define $fix__sterling-$-stdLib-$-not_mem : (Var_Item) -> (list (Var_Item)) -> prop by
$fix__sterling-$-stdLib-$-not_mem (Item) (nil);
$fix__sterling-$-stdLib-$-not_mem (Item) ((I)::(Rest)) :=
    (((I) = (Item)) -> (false)) /\ ($fix__sterling-$-stdLib-$-not_mem (Item) (Rest)).
Define $fix__sterling-$-stdLib-$-no_lookup : (list ($lib__pair (Var_Key) (Var_Item))) ->
                                             (Var_Key) -> prop by
$fix__sterling-$-stdLib-$-no_lookup (nil) (Key);
$fix__sterling-$-stdLib-$-no_lookup (($pair_c (K) (V))::(Rest)) (Key) :=
    (((K) = (Key)) -> (false)) /\ ($fix__sterling-$-stdLib-$-no_lookup (Rest) (Key)).
Define $fix__sterling-$-stdLib-$-lookup : (list ($lib__pair (Var_Key) (Var_Item))) ->
                                          (Var_Key) -> (Var_Item) -> prop by
$fix__sterling-$-stdLib-$-lookup (($pair_c (Key) (Value))::(Rest)) (Key) (Value);
$fix__sterling-$-stdLib-$-lookup (($pair_c (K) (V))::(Rest)) (Key) (Value) :=
    (((K) = (Key)) -> (false)) /\ ($fix__sterling-$-stdLib-$-lookup (Rest) (Key) (Value)).
Define $ext__0__walkthrough-$-host-$-is_ty : ($ty__walkthrough-$-host-$-ty) -> prop by
$ext__0__walkthrough-$-host-$-is_ty (walkthrough-$-host-$-arrowTy (Ty1) (Ty)) :=
    ($ext__0__walkthrough-$-host-$-is_ty (Ty1)) /\ ($ext__0__walkthrough-$-host-$-is_ty (Ty));
$ext__0__walkthrough-$-host-$-is_ty (walkthrough-$-host-$-intTy).
Define $ext__0__walkthrough-$-host-$-is_tm : ($ty__walkthrough-$-host-$-tm) -> prop by
$ext__0__walkthrough-$-host-$-is_tm (walkthrough-$-host-$-var (S)) := is_string (S);
$ext__0__walkthrough-$-host-$-is_tm (walkthrough-$-host-$-abs (S) (Ty) (Tm)) :=
    (is_string (S)) /\ (($ext__0__walkthrough-$-host-$-is_ty (Ty)) /\
    ($ext__0__walkthrough-$-host-$-is_tm (Tm)));
$ext__0__walkthrough-$-host-$-is_tm (walkthrough-$-host-$-app (Tm1) (Tm)) :=
    ($ext__0__walkthrough-$-host-$-is_tm (Tm1)) /\
    ($ext__0__walkthrough-$-host-$-is_tm (Tm));
$ext__0__walkthrough-$-host-$-is_tm (walkthrough-$-let-$-let (S) (Tm1) (Tm)) :=
    (is_string (S)) /\ (($ext__0__walkthrough-$-host-$-is_tm (Tm1)) /\
    ($ext__0__walkthrough-$-host-$-is_tm (Tm))).
Define $ext__1__walkthrough-$-host-$-typeOf :
          (list ($lib__pair (list $char) ($ty__walkthrough-$-host-$-ty))) ->
          ($ty__walkthrough-$-host-$-tm) -> ($ty__walkthrough-$-host-$-ty) -> prop by
$ext__1__walkthrough-$-host-$-typeOf (Ctx) (walkthrough-$-host-$-var (X)) (Ty) :=
    $fix__sterling-$-stdLib-$-lookup (Ctx) (X) (Ty);
$ext__1__walkthrough-$-host-$-typeOf (Ctx) (walkthrough-$-host-$-abs (X) (Ty1) (Body))
                                     (walkthrough-$-host-$-arrowTy (Ty1) (Ty2)) :=
    $ext__1__walkthrough-$-host-$-typeOf (($pair_c (X) (Ty1))::(Ctx)) (Body) (Ty2);
$ext__1__walkthrough-$-host-$-typeOf (Ctx) (walkthrough-$-host-$-app (T1) (T2)) (Ty2) :=
    exists Ty1, ($ext__1__walkthrough-$-host-$-typeOf (Ctx) (T1)
                     (walkthrough-$-host-$-arrowTy (Ty1) (Ty2))) /\
                ($ext__1__walkthrough-$-host-$-typeOf (Ctx) (T2) (Ty1));
$ext__1__walkthrough-$-host-$-typeOf (Ctx) (walkthrough-$-let-$-let (X) (T1) (T2)) (Ty2) :=
    exists Ty1, ($ext__1__walkthrough-$-host-$-typeOf (Ctx) (T1) (Ty1)) /\
                ($ext__1__walkthrough-$-host-$-typeOf (($pair_c (X) (Ty1))::(Ctx)) (T2) (Ty2)).
Define $ext__0__walkthrough-$-host-$-value : ($ty__walkthrough-$-host-$-tm) -> prop by
$ext__0__walkthrough-$-host-$-value (walkthrough-$-host-$-abs (X) (Ty) (T)).
Define $ext__2__walkthrough-$-host-$-subst : (list $char) -> ($ty__walkthrough-$-host-$-tm) ->
                   ($ty__walkthrough-$-host-$-tm) -> ($ty__walkthrough-$-host-$-tm) -> prop by
$ext__2__walkthrough-$-host-$-subst (X) (R) (walkthrough-$-host-$-var (Y))
                                    (walkthrough-$-host-$-var (Y)) := ((X) = (Y)) -> (false);
$ext__2__walkthrough-$-host-$-subst (X) (R) (walkthrough-$-host-$-var (X)) (R);
$ext__2__walkthrough-$-host-$-subst (X) (R) (walkthrough-$-host-$-abs (Y) (Ty) (B))
                                    (walkthrough-$-host-$-abs (Y) (Ty) (S)) :=
    (((X) = (Y)) -> (false)) /\ ($ext__2__walkthrough-$-host-$-subst (X) (R) (B) (S));
$ext__2__walkthrough-$-host-$-subst (X) (R) (walkthrough-$-host-$-abs (X) (Ty) (B))
                                    (walkthrough-$-host-$-abs (X) (Ty) (B));
$ext__2__walkthrough-$-host-$-subst (X) (R) (walkthrough-$-host-$-app (T1) (T2))
                                    (walkthrough-$-host-$-app (S1) (S2)) :=
    ($ext__2__walkthrough-$-host-$-subst (X) (R) (T1) (S1)) /\
    ($ext__2__walkthrough-$-host-$-subst (X) (R) (T2) (S2));
$ext__2__walkthrough-$-host-$-subst (X) (R) (walkthrough-$-let-$-let (Y) (T1) (T2))
                                    (walkthrough-$-let-$-let (Y) (S1) (S2)) :=
    (((X) = (Y)) -> (false)) /\ (($ext__2__walkthrough-$-host-$-subst (X) (R) (T1) (S1)) /\
    ($ext__2__walkthrough-$-host-$-subst (X) (R) (T2) (S2)));
$ext__2__walkthrough-$-host-$-subst (X) (R) (walkthrough-$-let-$-let (X) (T1) (T2))
                                    (walkthrough-$-let-$-let (X) (S1) (T2)) :=
    $ext__2__walkthrough-$-host-$-subst (X) (R) (T1) (S1).
Define $ext__0__walkthrough-$-host-$-eval : ($ty__walkthrough-$-host-$-tm) ->
                                            ($ty__walkthrough-$-host-$-tm) -> prop by
$ext__0__walkthrough-$-host-$-eval (walkthrough-$-host-$-app (T1) (T2))
                                   (walkthrough-$-host-$-app (T11) (T2)) :=
    $ext__0__walkthrough-$-host-$-eval (T1) (T11);
$ext__0__walkthrough-$-host-$-eval (walkthrough-$-host-$-app (T1) (T2))
                                   (walkthrough-$-host-$-app (T1) (T21)) :=
    ($ext__0__walkthrough-$-host-$-value (T1)) /\
    ($ext__0__walkthrough-$-host-$-eval (T2) (T21));
$ext__0__walkthrough-$-host-$-eval
           (walkthrough-$-host-$-app (walkthrough-$-host-$-abs (X) (Ty) (Body)) (T2)) (V) :=
    ($ext__0__walkthrough-$-host-$-value (T2)) /\
    ($ext__2__walkthrough-$-host-$-subst (X) (T2) (Body) (V));
$ext__0__walkthrough-$-host-$-eval (walkthrough-$-let-$-let (X) (T1) (T2))
                                   (walkthrough-$-let-$-let (X) (T11) (T2)) :=
    $ext__0__walkthrough-$-host-$-eval (T1) (T11);
$ext__0__walkthrough-$-host-$-eval (walkthrough-$-let-$-let (X) (T1) (T2)) (V) :=
    ($ext__0__walkthrough-$-host-$-value (T1)) /\
    ($ext__2__walkthrough-$-host-$-subst (X) (T1) (T2) (V)).
Define $proj__walkthrough-$-host-$-ty : ($ty__walkthrough-$-host-$-ty) ->
                                        ($ty__walkthrough-$-host-$-ty) -> prop by
$proj__walkthrough-$-host-$-ty (X257) (X258) := false.
Define $proj__walkthrough-$-host-$-tm :
          (list ($lib__pair (list $char) ($ty__walkthrough-$-host-$-ty))) ->
          ($ty__walkthrough-$-host-$-tm) -> ($ty__walkthrough-$-host-$-tm) -> prop by
$proj__walkthrough-$-host-$-tm (Ctx) (walkthrough-$-let-$-let (X) (T1) (T2))
         (walkthrough-$-host-$-app (walkthrough-$-host-$-abs (X) (Ty) (T2)) (T1)) :=
    $ext__1__walkthrough-$-host-$-typeOf (Ctx) (T1) (Ty).
Define $ext__0__walkthrough-$-big_step-$-big_step : ($ty__walkthrough-$-host-$-tm) ->
                                                    ($ty__walkthrough-$-host-$-tm) -> prop by
$ext__0__walkthrough-$-big_step-$-big_step (T) (T) := $ext__0__walkthrough-$-host-$-value (T);
$ext__0__walkthrough-$-big_step-$-big_step (T) (T2) :=
    exists T1, ($ext__0__walkthrough-$-host-$-eval (T) (T1)) /\
               ($ext__0__walkthrough-$-big_step-$-big_step (T1) (T2));
$ext__0__walkthrough-$-big_step-$-big_step (walkthrough-$-let-$-let (S) (Tm1) (Tm)) (T1) :=
    exists T_T,
       ($proj__walkthrough-$-host-$-tm (nil) (walkthrough-$-let-$-let (S) (Tm1) (Tm)) (T_T)) /\
       ($ext__0__walkthrough-$-big_step-$-big_step (T_T) (T1)).


%Stand-In Rules
Define $stand-in_rule__$ext__0__walkthrough-$-big_step-$-big_step :
          ($ty__walkthrough-$-host-$-tm) -> ($ty__walkthrough-$-host-$-tm) -> prop by
$stand-in_rule__$ext__0__walkthrough-$-big_step-$-big_step (A1) (A2).
Define $stand-in_rule__$ext__0__walkthrough-$-host-$-is_tm :
          ($ty__walkthrough-$-host-$-tm) -> prop by
$stand-in_rule__$ext__0__walkthrough-$-host-$-is_tm (X) :=
    exists A1 X_T, ($proj__walkthrough-$-host-$-tm (A1) (X) (X_T)) /\
                   ($ext__0__walkthrough-$-host-$-is_tm (X_T)).
Define $stand-in_rule__$ext__0__walkthrough-$-host-$-is_ty :
          ($ty__walkthrough-$-host-$-ty) -> prop by
$stand-in_rule__$ext__0__walkthrough-$-host-$-is_ty (X) :=
    exists X_T, ($proj__walkthrough-$-host-$-ty (X) (X_T)) /\
                ($ext__0__walkthrough-$-host-$-is_ty (X_T)).
Define $stand-in_rule__$ext__1__walkthrough-$-host-$-typeOf :
          (list ($lib__pair (list $char) ($ty__walkthrough-$-host-$-ty))) ->
          ($ty__walkthrough-$-host-$-tm) -> ($ty__walkthrough-$-host-$-ty) -> prop by
$stand-in_rule__$ext__1__walkthrough-$-host-$-typeOf (Ctx) (T) (Ty) :=
   exists T_T, ($proj__walkthrough-$-host-$-tm (Ctx) (T) (T_T)) /\
               ($ext__1__walkthrough-$-host-$-typeOf (Ctx) (T_T) (Ty)).
Define $stand-in_rule__$ext__0__walkthrough-$-host-$-eval :
          ($ty__walkthrough-$-host-$-tm) -> ($ty__walkthrough-$-host-$-tm) -> prop by
$stand-in_rule__$ext__0__walkthrough-$-host-$-eval (A1) (A2).
Define $stand-in_rule__$ext__2__walkthrough-$-host-$-subst :
          (list $char) -> ($ty__walkthrough-$-host-$-tm) -> ($ty__walkthrough-$-host-$-tm) ->
          ($ty__walkthrough-$-host-$-tm) -> prop by
$stand-in_rule__$ext__2__walkthrough-$-host-$-subst (A1) (A2) (A3) (A4).
Define $stand-in_rule__$ext__0__walkthrough-$-host-$-value :
          ($ty__walkthrough-$-host-$-tm) -> prop by
$stand-in_rule__$ext__0__walkthrough-$-host-$-value (A1).



/********************************************************************
 Proof-Level Definitions
 ********************************************************************/
Define $extSize__walkthrough-$-host-$-eval :
           $ty__walkthrough-$-host-$-tm -> $ty__walkthrough-$-host-$-tm ->
           $lib__integer -> prop by
$extSize__walkthrough-$-host-$-eval ((walkthrough-$-host-$-app) (T1) (T2))
                                    ((walkthrough-$-host-$-app) (T11) (T2)) (N) :=
    exists N1, (N1 = N) /\ ($extSize__walkthrough-$-host-$-eval (T1) (T11) (N1) );
$extSize__walkthrough-$-host-$-eval ((walkthrough-$-host-$-app) (T1) (T2))
                                    ((walkthrough-$-host-$-app) (T1) (T21)) (N) :=
    exists N1, (N1 = N) /\ (($ext__0__walkthrough-$-host-$-value (T1)) /\
               ($extSize__walkthrough-$-host-$-eval (T2) (T21) (N1) ));
$extSize__walkthrough-$-host-$-eval
          ((walkthrough-$-host-$-app) ((walkthrough-$-host-$-abs) (X) (Ty) (Body)) (T2))
          (V) (($posInt) ($zero)) :=
    ($ext__0__walkthrough-$-host-$-value (T2)) /\
    ($ext__2__walkthrough-$-host-$-subst (X) (T2) (Body) (V));
$extSize__walkthrough-$-host-$-eval ((walkthrough-$-let-$-let) (X) (T1) (T2))
                                    ((walkthrough-$-let-$-let) (X) (T11) (T2)) (N) :=
    exists N1, ($plus_integer (($posInt) (($succ) ($zero))) (N1) (N) ) /\
    ($extSize__walkthrough-$-host-$-eval (T1) (T11) (N1) );
$extSize__walkthrough-$-host-$-eval ((walkthrough-$-let-$-let) (X) (T1) (T2))
                                    (V) (($posInt) (($succ) ($zero))) :=
    ($ext__0__walkthrough-$-host-$-value (T1)) /\
    ($ext__2__walkthrough-$-host-$-subst (X) (T1) (T2) (V)).

Define $projRel__walkthrough-$-host-$-eval :
           $ty__walkthrough-$-host-$-tm -> $ty__walkthrough-$-host-$-tm -> prop by
$projRel__walkthrough-$-host-$-eval ((walkthrough-$-host-$-app) (T1) (T2))
                                    ((walkthrough-$-host-$-app) (T11) (T2)) :=
    $projRel__walkthrough-$-host-$-eval (T1) (T11);
$projRel__walkthrough-$-host-$-eval ((walkthrough-$-host-$-app) (T1) (T2))
                                    ((walkthrough-$-host-$-app) (T1) (T21)) :=
    ($ext__0__walkthrough-$-host-$-value (T1)) /\
    ($projRel__walkthrough-$-host-$-eval (T2) (T21));
$projRel__walkthrough-$-host-$-eval
          ((walkthrough-$-host-$-app) 
              ((walkthrough-$-host-$-abs) (X) (Ty) (Body)) (T2)) (V) :=
    ($ext__0__walkthrough-$-host-$-value (T2)) /\
    ($ext__2__walkthrough-$-host-$-subst (X) (T2) (Body) (V));
$projRel__walkthrough-$-host-$-eval ((walkthrough-$-let-$-let) (X) (T1) (T2))
                                    ((walkthrough-$-let-$-let) (X) (T11) (T2)) :=
    exists Ctx T_T T3,
      ($projRel__walkthrough-$-host-$-eval (T1) (T11)) /\
      (($proj__walkthrough-$-host-$-tm (Ctx)
            ((walkthrough-$-let-$-let) (X) (T1) (T2)) (T_T)) /\
      ($projRel__walkthrough-$-host-$-eval (T_T) (T3)));
$projRel__walkthrough-$-host-$-eval ((walkthrough-$-let-$-let) (X) (T1) (T2)) (V) :=
    exists Ctx T_T T3,
       (($ext__0__walkthrough-$-host-$-value (T1)) /\
       ($ext__2__walkthrough-$-host-$-subst (X) (T1) (T2) (V))) /\
       (($proj__walkthrough-$-host-$-tm (Ctx)
             ((walkthrough-$-let-$-let) (X) (T1) (T2)) (T_T)) /\
       ($projRel__walkthrough-$-host-$-eval (T_T) (T3))).



/********************************************************************
 Properties and Proofs
 ********************************************************************/
/*Start Theorem sterling:stdLib:lookup_unique*/
Theorem sterling-$-stdLib-$-lookup_unique[Key, Value] :
  forall L (Key : Key) (Value2 : Value) (Value1 : Value),
    ($fix__sterling-$-stdLib-$-lookup (L) (Key) (Value1)) ->
    ($fix__sterling-$-stdLib-$-lookup (L) (Key) (Value2)) -> Value1 = Value2. [Show Proof]
  
/*End sterling:stdLib:lookup_unique*/


/*Start Theorem sterling:stdLib:no_lookup*/
Theorem sterling-$-stdLib-$-no_lookup[Key, Value] : forall L (Key : Key) (Value : Value),
  ($fix__sterling-$-stdLib-$-no_lookup (L) (Key)) ->
  ($fix__sterling-$-stdLib-$-lookup (L) (Key) (Value)) -> false. [Show Proof]
  
/*End sterling:stdLib:no_lookup*/


/*Start Theorem sterling:stdLib:lookup_eq_or_not*/
Theorem sterling-$-stdLib-$-lookup_eq_or_not[Key, Value] :
  forall L (A : Key) (B : Key) (VB : Value) (VA : Value),
    ($fix__sterling-$-stdLib-$-lookup (L) (A) (VA)) ->
    ($fix__sterling-$-stdLib-$-lookup (L) (B) (VB)) -> (A = B) \/ ((A = B) -> false). [Show Proof]
  
/*End sterling:stdLib:lookup_eq_or_not*/


/*Start Theorem sterling:stdLib:lookup_mem*/
Theorem sterling-$-stdLib-$-lookup_mem[Key, Value] : forall L (Key : Key) (Value : Value),
  ($fix__sterling-$-stdLib-$-lookup (L) (Key) (Value)) ->
  $fix__sterling-$-stdLib-$-mem (($pair_c) (Key) (Value)) (L). [Show Proof]
  
/*End sterling:stdLib:lookup_mem*/


/*Start Theorem sterling:stdLib:no_lookup_mem*/
Theorem sterling-$-stdLib-$-no_lookup_mem[Key, Value] : forall L (Key : Key) (Value : Value),
  ($fix__sterling-$-stdLib-$-no_lookup (L) (Key)) ->
  ($fix__sterling-$-stdLib-$-mem (($pair_c) (Key) (Value)) (L)) -> false. [Show Proof]
  
/*End sterling:stdLib:no_lookup_mem*/


/*Start Theorem sterling:stdLib:no_lookup_mem_pair*/
Theorem sterling-$-stdLib-$-no_lookup_mem_pair[Key, Value] : forall L (P : $lib__pair Key Value) K,
  ($fix__sterling-$-stdLib-$-no_lookup (L) (K)) -> ($fix__sterling-$-stdLib-$-mem (P) (L)) ->
  exists X Y, P = ($pair_c) (X) (Y). [Show Proof]
  
/*End sterling:stdLib:no_lookup_mem_pair*/


/*Start Theorem sterling:stdLib:lookup_select*/
Theorem sterling-$-stdLib-$-lookup_select[Key, Value] : forall L (Key : Key) (Value : Value),
  ($fix__sterling-$-stdLib-$-lookup (L) (Key) (Value)) ->
  exists L', $fix__sterling-$-stdLib-$-select (($pair_c) (Key) (Value)) (L') (L). [Show Proof]
  
/*End sterling:stdLib:lookup_select*/


/*Start Theorem sterling:stdLib:no_lookup_select*/
Theorem sterling-$-stdLib-$-no_lookup_select[Key, Value] : forall L (Key : Key) (Value : Value) R,
  ($fix__sterling-$-stdLib-$-no_lookup (L) (Key)) ->
  ($fix__sterling-$-stdLib-$-select (($pair_c) (Key) (Value)) (R) (L)) -> false. [Show Proof]
  
/*End sterling:stdLib:no_lookup_select*/


/*Start Theorem sterling:stdLib:select_lookup*/
Theorem sterling-$-stdLib-$-select_lookup[Key, Value] :
  forall L (Key : Key) (K : Key) (Value : Value) (V : Value) R,
    ($fix__sterling-$-stdLib-$-lookup (L) (K) (V)) ->
    ($fix__sterling-$-stdLib-$-select (($pair_c) (Key) (Value)) (R) (L)) -> ((K = Key) -> false) ->
    $fix__sterling-$-stdLib-$-lookup (R) (K) (V). [Show Proof]
  
/*End sterling:stdLib:select_lookup*/


/*Start Theorem sterling:stdLib:no_lookup_after_select_before*/
Theorem sterling-$-stdLib-$-no_lookup_after_select_before[Key, Value] :
  forall (Key : Key) (K : Key) (V : Value) Rest L,
    ($fix__sterling-$-stdLib-$-no_lookup (Rest) (Key)) ->
    ($fix__sterling-$-stdLib-$-select (($pair_c) (K) (V)) (Rest) (L)) -> ((K = Key) -> false) ->
    $fix__sterling-$-stdLib-$-no_lookup (L) (Key). [Show Proof]
  
/*End sterling:stdLib:no_lookup_after_select_before*/


/*Start Theorem sterling:stdLib:no_lookup_before_select_after*/
Theorem sterling-$-stdLib-$-no_lookup_before_select_after[Key, Value] :
  forall (Key : Key) (P : $lib__pair Key Value) Rest L,
    ($fix__sterling-$-stdLib-$-no_lookup (L) (Key)) ->
    ($fix__sterling-$-stdLib-$-select (P) (Rest) (L)) ->
    $fix__sterling-$-stdLib-$-no_lookup (Rest) (Key). [Show Proof]
  
/*End sterling:stdLib:no_lookup_before_select_after*/


/*Start Theorem sterling:stdLib:lookup_after_select_before*/
Theorem sterling-$-stdLib-$-lookup_after_select_before[Key, Value] :
  forall (K : Key) (Key : Key) (V : Value) (Value : Value) L R,
    ($fix__sterling-$-stdLib-$-lookup (R) (K) (V)) ->
    ($fix__sterling-$-stdLib-$-select (($pair_c) (Key) (Value)) (R) (L)) -> ((K = Key) -> false) ->
    $fix__sterling-$-stdLib-$-lookup (L) (K) (V). [Show Proof]
  
/*End sterling:stdLib:lookup_after_select_before*/


/*Start Theorem sterling:stdLib:mem_select*/
Theorem sterling-$-stdLib-$-mem_select[Item] : forall L (X : Item),
  ($fix__sterling-$-stdLib-$-mem (X) (L)) ->
  exists L', $fix__sterling-$-stdLib-$-select (X) (L') (L). [Show Proof]
  
/*End sterling:stdLib:mem_select*/


/*Start Theorem sterling:stdLib:select_mem*/
Theorem sterling-$-stdLib-$-select_mem[Item] : forall L (X : Item) L',
  ($fix__sterling-$-stdLib-$-select (X) (L') (L)) -> $fix__sterling-$-stdLib-$-mem (X) (L). [Show Proof]
  
/*End sterling:stdLib:select_mem*/


/*Start Theorem sterling:stdLib:mem_after_select_before*/
Theorem sterling-$-stdLib-$-mem_after_select_before[Item] : forall L L' (Y : Item) (X : Item),
  ($fix__sterling-$-stdLib-$-select (X) (L') (L)) -> ($fix__sterling-$-stdLib-$-mem (Y) (L')) ->
  $fix__sterling-$-stdLib-$-mem (Y) (L). [Show Proof]
  
/*End sterling:stdLib:mem_after_select_before*/


/*Start Theorem sterling:stdLib:mem_before_select_after*/
Theorem sterling-$-stdLib-$-mem_before_select_after[Item] : forall L L' (Y : Item) (X : Item),
  ($fix__sterling-$-stdLib-$-select (X) (L') (L)) -> ($fix__sterling-$-stdLib-$-mem (Y) (L)) ->
  ((X = Y) -> false) -> $fix__sterling-$-stdLib-$-mem (Y) (L'). [Show Proof]
  
/*End sterling:stdLib:mem_before_select_after*/


/*Start Theorem sterling:stdLib:select_comm*/
Theorem sterling-$-stdLib-$-select_comm[Item] : forall L Rest Rest' (Y : Item) (X : Item),
  ($fix__sterling-$-stdLib-$-select (X) (Rest) (L)) ->
  ($fix__sterling-$-stdLib-$-select (Y) (Rest') (Rest)) ->
   exists R, ($fix__sterling-$-stdLib-$-select (Y) (R) (L)) /\
             ($fix__sterling-$-stdLib-$-select (X) (Rest') (R)). [Show Proof]
  
/*End sterling:stdLib:select_comm*/


/*Start Theorem sterling:stdLib:mem_append_left*/
Theorem sterling-$-stdLib-$-mem_append_left[A] : forall L1 L2 L (A : A),
  ($fix__sterling-$-stdLib-$-mem (A) (L1)) -> ($append (L1) (L2) (L)) ->
  $fix__sterling-$-stdLib-$-mem (A) (L). [Show Proof]
  
/*End sterling:stdLib:mem_append_left*/


/*Start Theorem sterling:stdLib:mem_append_right*/
Theorem sterling-$-stdLib-$-mem_append_right[A] : forall L1 L2 L (A : A),
  ($fix__sterling-$-stdLib-$-mem (A) (L2)) -> ($append (L1) (L2) (L)) ->
  $fix__sterling-$-stdLib-$-mem (A) (L). [Show Proof]
  
/*End sterling:stdLib:mem_append_right*/


/*Start Theorem sterling:stdLib:mem_append*/
Theorem sterling-$-stdLib-$-mem_append[A] : forall L1 L2 L (A : A),
  ($fix__sterling-$-stdLib-$-mem (A) (L)) -> ($append (L1) (L2) (L)) ->
  ($fix__sterling-$-stdLib-$-mem (A) (L1)) \/ ($fix__sterling-$-stdLib-$-mem (A) (L2)). [Show Proof]
  
/*End sterling:stdLib:mem_append*/


/*Start Theorem sterling:stdLib:not_mem*/
Theorem sterling-$-stdLib-$-not_mem[A] : forall (A : A) L,
  ($fix__sterling-$-stdLib-$-not_mem (A) (L)) ->
  ($fix__sterling-$-stdLib-$-mem (A) (L)) -> false. [Show Proof]
  
/*End sterling:stdLib:not_mem*/


/*Start Theorem sterling:stdLib:not_mem_select*/
Theorem sterling-$-stdLib-$-not_mem_select[A] : forall L (A : A) L',
  ($fix__sterling-$-stdLib-$-not_mem (A) (L)) ->
  ($fix__sterling-$-stdLib-$-select (A) (L') (L)) -> false. [Show Proof]
  
/*End sterling:stdLib:not_mem_select*/


/*Start Theorem sterling:stdLib:not_mem_after_select_before*/
Theorem sterling-$-stdLib-$-not_mem_after_select_before[A] : forall L L' (Y : A) (X : A),
  ($fix__sterling-$-stdLib-$-select (X) (L') (L)) ->
  ($fix__sterling-$-stdLib-$-not_mem (Y) (L')) -> ((X = Y) -> false) ->
  $fix__sterling-$-stdLib-$-not_mem (Y) (L). [Show Proof]
  
/*End sterling:stdLib:not_mem_after_select_before*/


/*Start Theorem sterling:stdLib:not_mem_before_select_after*/
Theorem sterling-$-stdLib-$-not_mem_before_select_after[A] : forall L L' (Y : A) (X : A),
  ($fix__sterling-$-stdLib-$-select (X) (L') (L)) -> ($fix__sterling-$-stdLib-$-not_mem (Y) (L)) ->
  $fix__sterling-$-stdLib-$-not_mem (Y) (L'). [Show Proof]
  
/*End sterling:stdLib:not_mem_before_select_after*/


/*Start Theorem sterling:stdLib:not_mem_append*/
Theorem sterling-$-stdLib-$-not_mem_append[A] : forall L1 L2 L (A : A),
  ($fix__sterling-$-stdLib-$-not_mem (A) (L1)) -> ($fix__sterling-$-stdLib-$-not_mem (A) (L2)) ->
  ($append (L1) (L2) (L)) -> $fix__sterling-$-stdLib-$-not_mem (A) (L). [Show Proof]
  
/*End sterling:stdLib:not_mem_append*/


/*Start Theorem sterling:stdLib:not_mem_append_back*/
Theorem sterling-$-stdLib-$-not_mem_append_back[A] : forall L1 L2 L (A : A),
  ($fix__sterling-$-stdLib-$-not_mem (A) (L)) -> ($append (L1) (L2) (L)) ->
  ($fix__sterling-$-stdLib-$-not_mem (A) (L1)) /\
  ($fix__sterling-$-stdLib-$-not_mem (A) (L2)). [Show Proof]
  
/*End sterling:stdLib:not_mem_append_back*/


/*Start Theorem sterling:stdLib:permutation_mem*/
Theorem sterling-$-stdLib-$-permutation_mem[Item] : forall (L : list Item) (M : list Item) I,
  ($fix__sterling-$-stdLib-$-permutation (L) (M)) -> ($fix__sterling-$-stdLib-$-mem (I) (L)) ->
  $fix__sterling-$-stdLib-$-mem (I) (M). [Show Proof]
  
/*End sterling:stdLib:permutation_mem*/


/*Start Theorem sterling:stdLib:perm_lemma*/
Theorem sterling-$-stdLib-$-perm_lemma[Item] : forall A B B' (X : Item),
  ($fix__sterling-$-stdLib-$-permutation (B') (A)) ->
  ($fix__sterling-$-stdLib-$-select (X) (B') (B)) ->
  $fix__sterling-$-stdLib-$-permutation (B) ((X)::(A)). [Show Proof]
  
/*End sterling:stdLib:perm_lemma*/


/*Start Theorem sterling:stdLib:permutation_symmetric*/
Theorem sterling-$-stdLib-$-permutation_symmetric[Item] : forall (M : list Item) (L : list Item),
  ($fix__sterling-$-stdLib-$-permutation (L) (M)) ->
  $fix__sterling-$-stdLib-$-permutation (M) (L). [Show Proof]
  
/*End sterling:stdLib:permutation_symmetric*/


/*Start Theorem sterling:stdLib:no_lookup_permutation*/
Theorem sterling-$-stdLib-$-no_lookup_permutation[Key, Value] :
   forall (L : list ($lib__pair Key Value)) (P : list ($lib__pair Key Value)) (Key : Key),
     ($fix__sterling-$-stdLib-$-no_lookup (L) (Key)) ->
     ($fix__sterling-$-stdLib-$-permutation (L) (P)) ->
     $fix__sterling-$-stdLib-$-no_lookup (P) (Key). [Show Proof]
  
/*End sterling:stdLib:no_lookup_permutation*/


/*Start Theorem sterling:stdLib:count_is_integer*/
Theorem sterling-$-stdLib-$-count_is_integer[Item] : forall (I : Item) L N,
  ($fix__sterling-$-stdLib-$-count (I) (L) (N)) -> is_integer (N). [Show Proof]
  
/*End sterling:stdLib:count_is_integer*/


/*Start Theorem sterling:stdLib:count_geq_0*/
Theorem sterling-$-stdLib-$-count_geq_0[Item] : forall (I : Item) L N,
  ($fix__sterling-$-stdLib-$-count (I) (L) (N)) ->
  $greatereq_integer (N) (($posInt) ($zero)). [Show Proof]
  
/*End sterling:stdLib:count_geq_0*/


/*Start Theorem sterling:stdLib:select_count*/
Theorem sterling-$-stdLib-$-select_count[Item] : forall (I : Item) L Rest N N',
  ($fix__sterling-$-stdLib-$-count (I) (L) (N)) ->
  ($fix__sterling-$-stdLib-$-select (I) (Rest) (L)) ->
  ($minus_integer (N) (($posInt) (($succ) ($zero))) (N')) ->
  $fix__sterling-$-stdLib-$-count (I) (Rest) (N'). [Show Proof]
  
/*End sterling:stdLib:select_count*/


/*Start Theorem sterling:stdLib:count_select*/
Theorem sterling-$-stdLib-$-count_select[Item] : forall (I : Item) L Rest N' N,
  ($fix__sterling-$-stdLib-$-count (I) (Rest) (N')) ->
  ($fix__sterling-$-stdLib-$-select (I) (Rest) (L)) ->
  ($plus_integer (($posInt) (($succ) ($zero))) (N') (N)) ->
  $fix__sterling-$-stdLib-$-count (I) (L) (N). [Show Proof]
  
/*End sterling:stdLib:count_select*/


/*Start Theorem sterling:stdLib:select_count_neq*/
Theorem sterling-$-stdLib-$-select_count_neq[Item] : forall (I : Item) (J : Item) L Rest N,
  ($fix__sterling-$-stdLib-$-count (I) (L) (N)) ->
  ($fix__sterling-$-stdLib-$-select (J) (Rest) (L)) -> ((I = J) -> false) ->
  $fix__sterling-$-stdLib-$-count (I) (Rest) (N). [Show Proof]
  
/*End sterling:stdLib:select_count_neq*/


/*Start Theorem sterling:stdLib:count_select_neq*/
Theorem sterling-$-stdLib-$-count_select_neq[Item] : forall (I : Item) (J : Item) L Rest N,
  ($fix__sterling-$-stdLib-$-count (I) (Rest) (N)) ->
  ($fix__sterling-$-stdLib-$-select (J) (Rest) (L)) -> ((I = J) -> false) ->
  $fix__sterling-$-stdLib-$-count (I) (L) (N). [Show Proof]
  
/*End sterling:stdLib:count_select_neq*/


/*Start Theorem sterling:stdLib:count_unique*/
Theorem sterling-$-stdLib-$-count_unique[Item] : forall (I : Item) NA NB L,
  ($fix__sterling-$-stdLib-$-count (I) (L) (NA)) ->
  ($fix__sterling-$-stdLib-$-count (I) (L) (NB)) -> NA = NB. [Show Proof]
  
/*End sterling:stdLib:count_unique*/


/*Start Theorem sterling:stdLib:count_mem*/
Theorem sterling-$-stdLib-$-count_mem[Item] : forall (I : Item) N L,
  ($fix__sterling-$-stdLib-$-count (I) (L) (N)) -> ($greater_integer (N) (($posInt) ($zero))) ->
  $fix__sterling-$-stdLib-$-mem (I) (L). [Show Proof]
  
/*End sterling:stdLib:count_mem*/


/*Start Theorem sterling:stdLib:count_not_mem*/
Theorem sterling-$-stdLib-$-count_not_mem[Item] : forall (I : Item) L,
  ($fix__sterling-$-stdLib-$-count (I) (L) (($posInt) ($zero))) ->
  ($fix__sterling-$-stdLib-$-mem (I) (L)) -> false. [Show Proof]
  
/*End sterling:stdLib:count_not_mem*/


/*Start Theorem sterling:stdLib:count_greater_0*/
Theorem sterling-$-stdLib-$-count_greater_0[Item] : forall (I : Item) L N,
  ($fix__sterling-$-stdLib-$-count (I) ((I)::(L)) (N)) ->
  $greater_integer (N) (($posInt) ($zero)). [Show Proof]
  
/*End sterling:stdLib:count_greater_0*/


/*Start Theorem sterling:stdLib:subset_mem*/
Theorem sterling-$-stdLib-$-subset_mem[A] : forall (Sub : list A) (Sup : list A) A,
  ($fix__sterling-$-stdLib-$-subset (Sub) (Sup)) -> ($fix__sterling-$-stdLib-$-mem (A) (Sub)) ->
  $fix__sterling-$-stdLib-$-mem (A) (Sup). [Show Proof]
  
/*End sterling:stdLib:subset_mem*/


/*Start Theorem sterling:stdLib:subset_trans*/
Theorem sterling-$-stdLib-$-subset_trans[A] : forall (B : list A) (C : list A) (A : list A),
  ($fix__sterling-$-stdLib-$-subset (A) (B)) -> ($fix__sterling-$-stdLib-$-subset (B) (C)) ->
  $fix__sterling-$-stdLib-$-subset (A) (C). [Show Proof]
  
/*End sterling:stdLib:subset_trans*/


/*Start Theorem sterling:stdLib:subset_add_right*/
Theorem sterling-$-stdLib-$-subset_add_right[A] : forall Sub Sup (A : A),
  ($fix__sterling-$-stdLib-$-subset (Sub) (Sup)) ->
  $fix__sterling-$-stdLib-$-subset (Sub) ((A)::(Sup)). [Show Proof]
  
/*End sterling:stdLib:subset_add_right*/


/*Start Theorem sterling:stdLib:permutation_counts*/
Theorem sterling-$-stdLib-$-permutation_counts[Item] : forall L P (I : Item) NL NP,
  ($fix__sterling-$-stdLib-$-permutation (L) (P)) ->
  ($fix__sterling-$-stdLib-$-count (I) (L) (NL)) ->
  ($fix__sterling-$-stdLib-$-count (I) (P) (NP)) -> NL = NP. [Show Proof]
  
/*End sterling:stdLib:permutation_counts*/


/*Start Theorem sterling:stdLib:domain_mem*/
Theorem sterling-$-stdLib-$-domain_mem[A, B] : forall L (A : A) (B : B) D,
  ($fix__sterling-$-stdLib-$-mem (($pair_c) (A) (B)) (L)) ->
  ($fix__sterling-$-stdLib-$-domain (L) (D)) -> $fix__sterling-$-stdLib-$-mem (A) (D). [Show Proof]
  
/*End sterling:stdLib:domain_mem*/


/*Start Theorem sterling:stdLib:mem_domain*/
Theorem sterling-$-stdLib-$-mem_domain[A, B] : forall (L : list ($lib__pair A B)) A D,
  ($fix__sterling-$-stdLib-$-domain (L) (D)) -> ($fix__sterling-$-stdLib-$-mem (A) (D)) ->
  exists B, $fix__sterling-$-stdLib-$-mem (($pair_c) (A) (B)) (L). [Show Proof]
  
/*End sterling:stdLib:mem_domain*/


/*Start Theorem sterling:stdLib:domain_select*/
Theorem sterling-$-stdLib-$-domain_select[A, B] : forall (L : list ($lib__pair A B)) LRest A B D,
  ($fix__sterling-$-stdLib-$-domain (L) (D)) ->
  ($fix__sterling-$-stdLib-$-select (($pair_c) (A) (B)) (LRest) (L)) ->
  exists DRest, ($fix__sterling-$-stdLib-$-select (A) (DRest) (D)) /\
                ($fix__sterling-$-stdLib-$-domain (LRest) (DRest)). [Show Proof]
  
/*End sterling:stdLib:domain_select*/


/*Start Theorem sterling:stdLib:domain_unique*/
Theorem sterling-$-stdLib-$-domain_unique[A, B] : forall (L : list ($lib__pair A B)) DA DB,
  ($fix__sterling-$-stdLib-$-domain (L) (DA)) ->
  ($fix__sterling-$-stdLib-$-domain (L) (DB)) -> DA = DB. [Show Proof]
  
/*End sterling:stdLib:domain_unique*/


/*Start Theorem sterling:stdLib:values_mem*/
Theorem sterling-$-stdLib-$-values_mem[A, B] : forall L (A : A) (B : B) V,
  ($fix__sterling-$-stdLib-$-mem (($pair_c) (A) (B)) (L)) ->
  ($fix__sterling-$-stdLib-$-values (L) (V)) -> $fix__sterling-$-stdLib-$-mem (B) (V). [Show Proof]
  
/*End sterling:stdLib:values_mem*/


/*Start Theorem sterling:stdLib:values_select*/
Theorem sterling-$-stdLib-$-values_select[A, B] : forall (L : list ($lib__pair A B)) LRest A B V,
  ($fix__sterling-$-stdLib-$-values (L) (V)) ->
  ($fix__sterling-$-stdLib-$-select (($pair_c) (A) (B)) (LRest) (L)) ->
  exists VRest, ($fix__sterling-$-stdLib-$-select (B) (VRest) (V)) /\
                ($fix__sterling-$-stdLib-$-values (LRest) (VRest)). [Show Proof]
  
/*End sterling:stdLib:values_select*/


/*Start Theorem sterling:stdLib:values_unique*/
Theorem sterling-$-stdLib-$-values_unique[A, B] : forall (L : list ($lib__pair A B)) VA VB,
  ($fix__sterling-$-stdLib-$-values (L) (VA)) ->
  ($fix__sterling-$-stdLib-$-values (L) (VB)) -> VA = VB. [Show Proof]
  
/*End sterling:stdLib:values_unique*/


/*Start Theorem sterling:stdLib:zip_unique*/
Theorem sterling-$-stdLib-$-zip_unique[A, B] : forall (L1 : list A) (L2 : list B) LA LB,
  ($fix__sterling-$-stdLib-$-zip (L1) (L2) (LA)) ->
  ($fix__sterling-$-stdLib-$-zip (L1) (L2) (LB)) -> LA = LB. [Show Proof]
  
/*End sterling:stdLib:zip_unique*/


/*Start Theorem sterling:stdLib:zip_mem_after*/
Theorem sterling-$-stdLib-$-zip_mem_after[A, B] : forall LA LB (A : A) (B : B) Z,
  ($fix__sterling-$-stdLib-$-zip (LA) (LB) (Z)) ->
  ($fix__sterling-$-stdLib-$-mem (($pair_c) (A) (B)) (Z)) ->
  ($fix__sterling-$-stdLib-$-mem (A) (LA)) /\ ($fix__sterling-$-stdLib-$-mem (B) (LB)). [Show Proof]
  
/*End sterling:stdLib:zip_mem_after*/


/*Start Theorem sterling:stdLib:zip_mem_before1*/
Theorem sterling-$-stdLib-$-zip_mem_before1[A, B] : forall LA (LB : list B) (A : A) Z,
  ($fix__sterling-$-stdLib-$-zip (LA) (LB) (Z)) -> ($fix__sterling-$-stdLib-$-mem (A) (LA)) ->
  exists B, $fix__sterling-$-stdLib-$-mem (($pair_c) (A) (B)) (Z). [Show Proof]
  
/*End sterling:stdLib:zip_mem_before1*/


/*Start Theorem sterling:stdLib:zip_mem_before2*/
Theorem sterling-$-stdLib-$-zip_mem_before2[A, B] : forall (LA : list A) LB (B : B) Z,
  ($fix__sterling-$-stdLib-$-zip (LA) (LB) (Z)) -> ($fix__sterling-$-stdLib-$-mem (B) (LB)) ->
  exists A, $fix__sterling-$-stdLib-$-mem (($pair_c) (A) (B)) (Z). [Show Proof]
  
/*End sterling:stdLib:zip_mem_before2*/


/*Start Theorem sterling:stdLib:drop_is_integer*/
Theorem sterling-$-stdLib-$-drop_is_integer[A] : forall N (R : list A) (L : list A),
  ($fix__sterling-$-stdLib-$-drop (N) (L) (R)) -> is_integer (N). [Show Proof]
  
/*End sterling:stdLib:drop_is_integer*/


/*Start Theorem sterling:stdLib:drop_geq_0*/
Theorem sterling-$-stdLib-$-drop_geq_0[A] : forall N (R : list A) (L : list A),
  ($fix__sterling-$-stdLib-$-drop (N) (L) (R)) ->
  $greatereq_integer (N) (($posInt) ($zero)). [Show Proof]
  
/*End sterling:stdLib:drop_geq_0*/


/*Start Theorem sterling:stdLib:drop_unique*/
Theorem sterling-$-stdLib-$-drop_unique[A] : forall N (RA : list A) (RB : list A) (L : list A),
  ($fix__sterling-$-stdLib-$-drop (N) (L) (RA)) ->
  ($fix__sterling-$-stdLib-$-drop (N) (L) (RB)) -> RA = RB. [Show Proof]
  
/*End sterling:stdLib:drop_unique*/


/*Start Theorem sterling:stdLib:append_drop*/
Theorem sterling-$-stdLib-$-append_drop[A] : forall N (L2 : list A) (L : list A) (L1 : list A),
  ($append (L1) (L2) (L)) -> (extensibella-$-stdLib-$-length (L1) (N)) ->
  $fix__sterling-$-stdLib-$-drop (N) (L) (L2). [Show Proof]
  
/*End sterling:stdLib:append_drop*/


/*Start Theorem sterling:stdLib:take_is_integer*/
Theorem sterling-$-stdLib-$-take_is_integer[A] : forall N (F : list A) (L : list A),
  ($fix__sterling-$-stdLib-$-take (N) (L) (F)) -> is_integer (N). [Show Proof]
  
/*End sterling:stdLib:take_is_integer*/


/*Start Theorem sterling:stdLib:take_geq_0*/
Theorem sterling-$-stdLib-$-take_geq_0[A] : forall N (F : list A) (L : list A),
  ($fix__sterling-$-stdLib-$-take (N) (L) (F)) ->
  $greatereq_integer (N) (($posInt) ($zero)). [Show Proof]
  
/*End sterling:stdLib:take_geq_0*/


/*Start Theorem sterling:stdLib:take_unique*/
Theorem sterling-$-stdLib-$-take_unique[A] : forall N (RA : list A) (RB : list A) (L : list A),
  ($fix__sterling-$-stdLib-$-take (N) (L) (RA)) ->
  ($fix__sterling-$-stdLib-$-take (N) (L) (RB)) -> RA = RB. [Show Proof]
  
/*End sterling:stdLib:take_unique*/


/*Start Theorem sterling:stdLib:take_length*/
Theorem sterling-$-stdLib-$-take_length[A] : forall N (R : list A) (L : list A),
  ($fix__sterling-$-stdLib-$-take (N) (L) (R)) -> extensibella-$-stdLib-$-length (R) (N). [Show Proof]
  
/*End sterling:stdLib:take_length*/


/*Start Theorem sterling:stdLib:append_take*/
Theorem sterling-$-stdLib-$-append_take[A] : forall N (L2 : list A) (L : list A) (L1 : list A),
  ($append (L1) (L2) (L)) -> (extensibella-$-stdLib-$-length (L1) (N)) ->
  $fix__sterling-$-stdLib-$-take (N) (L) (L1). [Show Proof]
  
/*End sterling:stdLib:append_take*/


/*Start Theorem sterling:stdLib:range_is*/
Theorem sterling-$-stdLib-$-range_is : forall Low High R,
  (is_integer (Low)) -> ($fix__sterling-$-stdLib-$-range (Low) (High) (R)) ->
  is_list (is_integer) (R). [Show Proof]
  
/*End sterling:stdLib:range_is*/


/*Start Theorem sterling:stdLib:is_list_int_mem*/
Theorem sterling-$-stdLib-$-is_list_int_mem : forall L (X : $lib__integer),
  (is_list (is_integer) (L)) -> ($fix__sterling-$-stdLib-$-mem (X) (L)) -> is_integer (X). [Show Proof]
  
/*End sterling:stdLib:is_list_int_mem*/


/*Start Theorem sterling:stdLib:range_low_lesseq*/
Theorem sterling-$-stdLib-$-range_low_lesseq : forall Low High R X,
  (is_integer (Low)) -> ($fix__sterling-$-stdLib-$-range (Low) (High) (R)) ->
  ($fix__sterling-$-stdLib-$-mem (X) (R)) -> $lesseq_integer (Low) (X). [Show Proof]
  
/*End sterling:stdLib:range_low_lesseq*/


/*Start Theorem sterling:stdLib:range_high_lesseq*/
Theorem sterling-$-stdLib-$-range_high_lesseq : forall Low High R X,
  (is_integer (Low)) -> ($fix__sterling-$-stdLib-$-range (Low) (High) (R)) ->
  ($fix__sterling-$-stdLib-$-mem (X) (R)) -> $lesseq_integer (X) (High). [Show Proof]
  
/*End sterling:stdLib:range_high_lesseq*/


/*Start Theorem sterling:stdLib:in_range*/
Theorem sterling-$-stdLib-$-in_range : forall Low High R X,
  (is_integer (Low)) -> (is_integer (X)) -> ($fix__sterling-$-stdLib-$-range (Low) (High) (R)) ->
  ($lesseq_integer (Low) (X)) -> ($lesseq_integer (X) (High)) ->
  $fix__sterling-$-stdLib-$-mem (X) (R). [Show Proof]
  
/*End sterling:stdLib:in_range*/


/*Start Theorem sterling:stdLib:range_unique*/
Theorem sterling-$-stdLib-$-range_unique : forall Low High R1 R2,
  ($fix__sterling-$-stdLib-$-range (Low) (High) (R1)) ->
  ($fix__sterling-$-stdLib-$-range (Low) (High) (R2)) -> R1 = R2. [Show Proof]
  
/*End sterling:stdLib:range_unique*/


/*Start Theorem sterling:stdLib:range_smaller_exists*/
Theorem sterling-$-stdLib-$-range_smaller_exists : forall Low High R Low',
  (is_integer (Low)) -> (is_integer (Low')) ->
  ($fix__sterling-$-stdLib-$-range (Low) (High) (R)) ->
  ($less_integer (Low) (Low')) ->
  exists R', $fix__sterling-$-stdLib-$-range (Low') (High) (R'). [Show Proof]
  
/*End sterling:stdLib:range_smaller_exists*/


/*Start Theorem sterling:stdLib:range_subset*/
Theorem sterling-$-stdLib-$-range_subset : forall Low Low' High R R',
  (is_integer (Low)) -> (is_integer (Low')) ->
  ($fix__sterling-$-stdLib-$-range (Low) (High) (R)) ->
  ($fix__sterling-$-stdLib-$-range (Low') (High) (R')) -> ($less_integer (Low) (Low')) ->
  $fix__sterling-$-stdLib-$-subset (R') (R). [Show Proof]
  
/*End sterling:stdLib:range_subset*/


/*Start Theorem sterling:stdLib:range_select_unique*/
Theorem sterling-$-stdLib-$-range_select_unique : forall Low High R X Rest Rest',
  (is_integer (Low)) -> ($fix__sterling-$-stdLib-$-range (Low) (High) (R)) ->
  ($fix__sterling-$-stdLib-$-select (X) (Rest) (R)) ->
  ($fix__sterling-$-stdLib-$-select (X) (Rest') (R)) -> Rest = Rest'. [Show Proof]
  
/*End sterling:stdLib:range_select_unique*/


/*Start Theorem sterling:stdLib:range_exists*/
Theorem sterling-$-stdLib-$-range_exists : forall Low High,
  (is_integer (Low)) -> (is_integer (High)) ->
  exists R, $fix__sterling-$-stdLib-$-range (Low) (High) (R). [Show Proof]
  
/*End sterling:stdLib:range_exists*/


/*Start Extensible_Theorem walkthrough:host:typeOf_unique*/
Theorem walkthrough-$-host-$-typeOf_unique : forall Ctx T TyA TyB,
  ($ext__1__walkthrough-$-host-$-typeOf (Ctx) (T) (TyA)) ->
  ($ext__1__walkthrough-$-host-$-typeOf (Ctx) (T) (TyB)) -> TyA = TyB. [Show Proof]
  

/*End walkthrough:host:typeOf_unique*/


/*Start Extensible_Theorem walkthrough:host:ty_lookup*/
Theorem walkthrough-$-host-$-ty_lookup : forall Ctx1 Ctx2 T Ty,
  ($ext__1__walkthrough-$-host-$-typeOf (Ctx1) (T) (Ty)) ->
  (forall X XTy, ($fix__sterling-$-stdLib-$-lookup (Ctx1) (X) (XTy)) ->
  $fix__sterling-$-stdLib-$-lookup (Ctx2) (X) (XTy)) ->
  $ext__1__walkthrough-$-host-$-typeOf (Ctx2) (T) (Ty). [Show Proof]
  

/*End walkthrough:host:ty_lookup*/


/*Start Theorem walkthrough:host:empty_ty_any*/
Theorem walkthrough-$-host-$-empty_ty_any : forall T Ty Ctx,
  ($ext__1__walkthrough-$-host-$-typeOf (nil) (T) (Ty)) ->
  $ext__1__walkthrough-$-host-$-typeOf (Ctx) (T) (Ty). [Show Proof]
  
/*End walkthrough:host:empty_ty_any*/


/*Start Extensible_Theorem walkthrough:host:subst_type_preservation*/
Theorem walkthrough-$-host-$-subst_type_preservation : forall T Ctx X XTy Ty R S,
  ($ext__1__walkthrough-$-host-$-typeOf ((($pair_c) (X) (XTy))::(Ctx)) (T) (Ty)) ->
  ($ext__2__walkthrough-$-host-$-subst (X) (R) (T) (S)) ->
  ($ext__1__walkthrough-$-host-$-typeOf (nil) (R) (XTy)) ->
  $ext__1__walkthrough-$-host-$-typeOf (Ctx) (S) (Ty). [Show Proof]
  

/*End walkthrough:host:subst_type_preservation*/


/*Start Extensible_Theorem walkthrough:host:type_preservation*/
Theorem walkthrough-$-host-$-type_preservation : forall T Ty T',
  ($ext__1__walkthrough-$-host-$-typeOf (nil) (T) (Ty)) ->
  ($ext__0__walkthrough-$-host-$-eval (T) (T')) ->
  $ext__1__walkthrough-$-host-$-typeOf (nil) (T') (Ty). [Show Proof]
  

/*End walkthrough:host:type_preservation*/


/*Start Projection Constraint walkthrough:host:proj_type_same*/
Theorem walkthrough-$-host-$-proj_type_same  : forall G T Ty T_T,
  ($proj__walkthrough-$-host-$-tm (G) (T) (T_T)) ->
  ($ext__1__walkthrough-$-host-$-typeOf (G) (T) (Ty)) ->
  $ext__1__walkthrough-$-host-$-typeOf (G) (T_T) (Ty). [Show Proof]
  
/*End walkthrough:host:proj_type_same*/


/*Start Ext_Size for walkthrough:host:eval*/
Theorem walkthrough-$-host-$-ext_size_pos_eval : forall T T' N,
  ($extSize__walkthrough-$-host-$-eval (T) (T') (N) ) ->
  $lesseq_integer (($posInt) ($zero)) (N). [Show Proof]


Theorem walkthrough-$-host-$-ext_size_is_int_eval : forall T T' N,
  ($extSize__walkthrough-$-host-$-eval (T) (T') (N) ) ->
  extensibella-$-stdLib-$-is_integer (N). [Show Proof]


Theorem walkthrough-$-host-$-drop_ext_size_eval : forall T T' N,
  ($extSize__walkthrough-$-host-$-eval (T) (T') (N) ) ->
  $ext__0__walkthrough-$-host-$-eval (T) (T'). [Show Proof]


Theorem walkthrough-$-host-$-add_ext_size_eval : forall T T',
  ($ext__0__walkthrough-$-host-$-eval (T) (T') ) ->
  exists N, $extSize__walkthrough-$-host-$-eval (T) (T') (N). [Show Proof]


/*End Ext_Size for walkthrough:host:eval*/


/*Start Proj_Rel for walkthrough:host:eval*/
Theorem walkthrough-$-host-$-drop_proj_rel_eval : forall T T',
  ($projRel__walkthrough-$-host-$-eval (T) (T') ) ->
  $ext__0__walkthrough-$-host-$-eval (T) (T'). [Show Proof]


/*End Proj_Rel for walkthrough:host:eval*/


/*Start Ext_Ind for walkthrough:host:eval*/
Theorem $toProjRel__$ext__0__walkthrough-$-host-$-eval : forall N G T T' Ty,
  ($extSize__walkthrough-$-host-$-eval (T) (T') (N) ) ->
  (extensibella-$-stdLib-$-acc (N) ) ->
  ($ext__1__walkthrough-$-host-$-typeOf (G) (T) (Ty)) ->
  $projRel__walkthrough-$-host-$-eval (T) (T') . [Show Proof]


Theorem walkthrough-$-host-$-add_proj_rel_eval : forall G T T' Ty,
  ($ext__0__walkthrough-$-host-$-eval (T) (T') ) ->
  ($ext__1__walkthrough-$-host-$-typeOf (G) (T) (Ty)) ->
  $projRel__walkthrough-$-host-$-eval (T) (T') . [Show Proof]

/*End Ext_Ind for walkthrough:host:eval*/


/*Start Extensible_Theorem walkthrough:big_step:big_step_type_preservation*/
Theorem walkthrough-$-big_step-$-big_step_type_preservation : forall T Ty T',
  ($ext__1__walkthrough-$-host-$-typeOf (nil) (T) (Ty)) ->
  ($ext__0__walkthrough-$-big_step-$-big_step (T) (T')) ->
  $ext__1__walkthrough-$-host-$-typeOf (nil) (T') (Ty). [Show Proof]
  

/*End walkthrough:big_step:big_step_type_preservation*/

In this file, in addition to the language definitions and theorems about standard library relations, of which there are many, we have the Abella versions of the proofs for the theorems introduced by the host language and the big step extension. These are down at the end of the file. Note they are in the same order as in the composed module, an order that maintains the order used by the host language and the order used by the big step extension. Each of the proofs of these theorems is built by taking pieces of the proofs for each module and combining them.

If we look at the proof for type preservation, pulled out here, we see we start the proof by induction and case analysis on the key relation, giving us five cases:

Theorem walkthrough-$-host-$-type_preservation : forall T Ty T',
  ($ext__1__walkthrough-$-host-$-typeOf (nil) (T) (Ty)) ->
  ($ext__0__walkthrough-$-host-$-eval (T) (T')) ->
  $ext__1__walkthrough-$-host-$-typeOf (nil) (T') (Ty).
induction on 2. 
 intros Ty Ev. Ev: case Ev (keep).
  Ty: case Ty. apply IH to Ty Ev1. search. 
  Ty: case Ty. apply IH to Ty1 Ev2. search. 
  Ty: case Ty. Ty: case Ty. apply walkthrough-$-host-$-subst_type_preservation to Ty Ev2 Ty1. search.
  Ty: case Ty. apply IH to Ty Ev1. search. 
  Ty: case Ty. apply walkthrough-$-host-$-subst_type_preservation to Ty1 Ev2 Ty. search.
Compare these to the three cases given by the host language
%E-App-Step1
 Ty: case Ty. apply IH to Ty Ev1. search.
%E-App-Step2
 Ty: case Ty. apply IH to Ty1 Ev2. search.
%E-App-Subst
 Ty: case Ty. Ty: case Ty.
 apply subst_type_preservation to Ty Ev2 Ty1. search.
and the two given by the let extension
%E-Let-Step
 Ty: case Ty. apply IH to Ty Ev1. search.
%E-Let-Subst
 Ty: case Ty. apply subst_type_preservation to Ty1 Ev2 Ty. search.
We see they are the same, modulo the use of full names for the lemmas, because the full proof is built by taking the cases from the proofs from the individual modules and putting them together. The same can be observed for the other extensible theorems from the host language, including the projection constraint and Ext_Ind proof, both of which are declared in Abella with Theorem, the only type of theorem declaration in Abella.

We can see a similar thing with the proof of the big step extension's property, where we have three cases:

Theorem walkthrough-$-big_step-$-big_step_type_preservation : forall T Ty T',
  ($ext__1__walkthrough-$-host-$-typeOf (nil) (T) (Ty)) ->
  ($ext__0__walkthrough-$-big_step-$-big_step (T) (T')) ->
  $ext__1__walkthrough-$-host-$-typeOf (nil) (T') (Ty).
induction on 2. 
 intros Ty Big. Big: case Big (keep).
  search.
  apply walkthrough-$-host-$-type_preservation to Ty Big1. apply IH to _ Big2. search.
  apply walkthrough-$-host-$-proj_type_same to Big1 Ty. apply IH to _ Big2. search.
Keep in mind the definition of big_step in the composed language:
Define $ext__0__walkthrough-$-big_step-$-big_step : ($ty__walkthrough-$-host-$-tm) ->
                                                    ($ty__walkthrough-$-host-$-tm) -> prop by
$ext__0__walkthrough-$-big_step-$-big_step (T) (T) := $ext__0__walkthrough-$-host-$-value (T);
$ext__0__walkthrough-$-big_step-$-big_step (T) (T2) :=
    exists T1, ($ext__0__walkthrough-$-host-$-eval (T) (T1)) /\
               ($ext__0__walkthrough-$-big_step-$-big_step (T1) (T2));
$ext__0__walkthrough-$-big_step-$-big_step (walkthrough-$-let-$-let (S) (Tm1) (Tm)) (T1) :=
    exists T_T,
       ($proj__walkthrough-$-host-$-tm (nil) (walkthrough-$-let-$-let (S) (Tm1) (Tm)) (T_T)) /\
       ($ext__0__walkthrough-$-big_step-$-big_step (T_T) (T1)).
We have three clauses, one corresponding to the Big-End rule, one corresponding to the Big-Step rule, and one corresponding to the Big-D rule instantiated for the let construct from the let extension. When the big step extension wrote its proof, it knew the first two rules, but its proof for the third rule was generic, as it did not know the let constructor:
%Big-End
 search.
%Big-Step
 apply type_preservation to Ty Big1. apply IH to _ Big2. search.
%Big-D
 apply proj_type_same to Big1 Ty. apply IH to _ Big2. search.
Because of the restrictions Extensibella places on proofs, as we saw above when writing the generic proof, this generic proof can be used even when the rule is instantiated for let, or any other construct. If our composed language contained more constructs from other extensions, this proof would be present with one copy for each, and it would be valid for all.

Note that the lemmas ext_size_is_int_typeOf and ext_size_pos_typeOf we used in the proof of Ext_Ind in the let extension have been given full, automatically-generated proofs in the composition, validating our use of them as lemmas by showing they do hold.

Moving Forward

This concludes our walkthrough of modular metatheory in Extensibella. A few places to go from here: