7. MoreStlc: More on the Simply Typed Lambda-Calculus
7.1. Simple Extensions to STLC
The simply typed lambda-calculus has a rich enough structure to make its theoretical properties interesting, but it is not much of a programming language!
In this chapter, we begin to close the gap with real-world languages by introducing a number of familiar features that have straightforward treatments at the level of typing.
7.1.1. Numbers
As we saw in the StlcExtended exercises at the end of the StlcProp
chapter, adding types, constants, and primitive operations for
natural numbers is easy - basically just a matter of combining
the Types and Stlc chapters. Adding more realistic
numeric types like machine integers and floats is also
straightforward, though of course the specifications of the
numeric primitives become more fiddly.
When writing a complex expression, it is useful to be able
to give names to some of its subexpressions to avoid repetition
and increase readability. Most languages provide one or more ways
of doing this. In OCaml and Haskell, for example, we can write let x = t₁ in t₂ to mean
"reduce the expression t₁ to a value and
bind the name x to this value while reducing t₂."
Our let-binder follows OCaml in choosing a standard
call-by-value evaluation order, where the let-bound term must
be fully reduced before reduction of the let-body can begin.
The typing rule let tells us that the type of a let can be
calculated by calculating the type of the let-bound term,
extending the context with a binding with this type, and in this
enriched context calculating the type of the body (which is then
the type of the whole let expression).
At this point in the book, it's probably easier simply to look at the rules defining this new feature than to wade through a lot of English text conveying the same information. Here they are:
Syntax:
t ::= Terms
| ... (other terms same as before)
| let x = t₁ in t₂ let-binding
Reduction:
t₁ ⟶ t₁'
------------------------------------- (let₁)
let x = t₁ in t₂ ⟶ let x = t₁' in t₂
--------------------------------- (letValue)
let x = v₁ in t₂ ⟶ [x := v₁] t₂
Typing:
Γ ⊢ t₁ ⦂ τ₁ x ↦ τ₁ ; Γ ⊢ t₂ ⦂ τ₂
------------------------------------------- (let)
Γ ⊢ let x = t₁ in t₂ ⦂ τ₂
7.1.2. Pairs
Our functional programming examples in Lean have made frequent use of pairs of values. The type of such a pair is called a product type.
The formalization of pairs is almost too simple to be worth discussing. However, let's look briefly at the various parts of the definition to emphasize the common pattern.
In Lean, there are two ways of extracting the components of a pair:
pattern matching and the projection operators fst and snd.
Just for fun, let's do our pairs the latter way. For
example, here's how we'd write a function that takes a pair of
numbers and returns the pair of their sum and difference:
λX : Nat × Nat.
let Sum = fst X + snd X in
let Diff = fst X - snd X in
(Sum, Diff)
Adding pairs to the simply typed lambda-calculus, then, involves
adding two new forms of term - pairing, written (t₁,t₂), and
projection, written fst t for the first projection from t and
snd t for the second projection - plus one new type constructor,
τ₁ × τ₂, called the product of τ₁ and τ₂.
Syntax:
t ::= Terms
| ...
| (t₁, t₂) pair
| fst t first projection
| snd t second projection
v ::= Values
| ...
| (v₁, v₂) pair value
τ ::= Types
| ...
| τ₁ × τ₂ product type
For reduction, we need several new rules specifying how pairs and projection behave.
t₁ ⟶ t₁'
-------------------- (pair₁)
(t₁,t₂) ⟶ (t₁',t₂)
t₂ ⟶ t₂'
-------------------- (pair₂)
(v₁,t₂) ⟶ (v₁,t₂')
t ⟶ t'
------------------ (fst₁)
fst t ⟶ fst t'
------------------ (fstPair)
fst (v₁,v₂) ⟶ v₁
t ⟶ t'
------------------ (snd₁)
snd t ⟶ snd t'
------------------ (sndPair)
snd (v₁,v₂) ⟶ v₂
Rules fstPair and sndPair say that, when a fully
reduced pair meets a first or second projection, the result is
the appropriate component. The congruence rules fst₁ and
snd₁ allow reduction to proceed under projections, when the
term being projected from has not yet been fully reduced.
pair₁ and pair₂ reduce the parts of pairs: first the
left part, and then - when a value appears on the left - the right
part. The ordering arising from the use of the metavariables v
and t in these rules enforces a left-to-right evaluation
strategy for pairs. (Note the implicit convention that
metavariables like v and v₁ can only denote values.) We've
also added a clause to the definition of values, above, specifying
that (v₁,v₂) is a value. The fact that the components of a pair
value must themselves be values ensures that a pair passed as an
argument to a function will be fully reduced before the function
body starts executing.
The typing rules for pairs and projections are straightforward.
Γ ⊢ t₁ ⦂ τ₁ Γ t₂ ⦂ τ₂
------------------------------ (pair)
Γ ⊢(t₁, t₂) ⦂ τ₁ × τ₂
Γ ⊢ t ⦂ τ₁ × τ₂
----------------------- (fst)
Γ ⊢ fst t ⦂ τ₁
Γ ⊢ t ⦂ τ₁ × τ₂
----------------------- (snd)
Γ ⊢ snd t ⦂ τ₂
pair says that (t₁, t₂) has type τ₁ × τ₂ if t₁ has
type τ₁ and t₂ has type τ₂. Conversely, fst and snd
tell us that, if t has a product type τ₁ × τ₂ (i.e., if it
will reduce to a pair), then the types of the projections from
this pair are τ₁ and τ₂.
7.1.3. Unit
Another handy base type is the singleton type Unit.
It has a single element - the term constant unit (with a small u) -
and a typing rule making unit an element of Unit. We
also add unit to the set of possible values - indeed, unit is
the only possible result of reducing an expression of type Unit.
Syntax:
t ::= Terms
| ... (other terms same as before)
| unit unit
v ::= Values
| ...
| unit unit value
τ ::= Types
| ...
| Unit unit type
Typing:
---------------- (unit)
Γ ⊢ unit ⦂ Unit
It may seem a little strange to bother defining a type that has just one element -- after all, wouldn't every computation living in such a type be trivial?
This is a fair question, and indeed in the STLC the Unit type is
not especially critical (though we'll see two uses for it below).
Where Unit really comes in handy is in richer languages with
side effects -- e.g., assignment statements that mutate
variables or pointers, exceptions and other sorts of nonlocal
control structures, etc. In such languages, it is convenient to
have a type for the (trivial) result of an expression that is
evaluated only for its effect.
Is unit the only term of type Unit?
(A) Yes
(B) No
Show solution
No! For instance λX:Unit. X unit is also a term of type Unit.
7.1.4. Sums
Many programs need to deal with values that can take two distinct forms. For example, we might identify students in a university database using either their name or their id number. A search function might return either a matching value or an error code.
These are specific examples of a binary sum type (sometimes called a disjoint union), which describes a set of values drawn from one of two given types, e.g.:
Nat + Bool
We create elements of these types by tagging elements of
the component types. For example, if n is a Nat then inl n
is an element of Nat + Bool; similarly, if b is a Bool then
inr b is a Nat + Bool. The names of the tags inl and inr
arise from thinking of them as functions
inl ⦂ Nat → Nat + Bool
inr ⦂ Bool → Nat + Bool
that "inject" elements of Nat or Bool into the left and right
components of the sum type Nat + Bool. (But note that we don't
actually treat them as functions in the way we formalize them:
inl and inr are keywords, and inl t and inr t are primitive
syntactic forms, not function applications.)
In general, the elements of a type τ₁ + τ₂ consist of the
elements of τ₁ tagged with the token inl, plus the elements of
τ₂ tagged with inr.
(As we've seen in Lean programming, one important use of sums is signaling errors:
Div ⦂ Nat → Nat → (Nat + Unit)
Div =
λX:Nat. λY:Nat,
if iszero Y then
inr unit
else
inl ...
The type Nat + Unit above is in fact isomorphic to Option Nat in Lean -
i.e., it's easy to write functions that translate back and forth.
To use elements of sum types, we introduce a case
construct (a very simplified form of Lean's match) to destruct
them. For example, the following procedure converts a Nat + Bool into a Nat:
GetNat ⦂ Nat + Bool → Nat
GetNat =
λX:Nat + Bool,
case X of
inl N => N
| inr B => if B then 1 else 0
More formally...
Syntax:
t ::= Terms
| ... (other terms same as before)
| inl τ₂ t₁ tagging (left)
| inr τ₁ t₂ tagging (right)
| case t of case analysis
inl x₁ => t₁
| inr x₂ => t₂
v ::= Values
| ...
| inl τ₂ v₁ tagged value (left)
| inr τ₁ v₂ tagged value (right)
τ ::= Types
| ...
| τ₁ + τ₂ sum type
Reduction:
t₁ ⟶ t₁'
------------------------ (inl)
inl τ₂ t₁ ⟶ inl τ₂ t₁'
t₂ ⟶ t₂'
------------------------ (inr)
inr τ₁ t₂ ⟶ inr τ₁ t₂'
t ⟶ t'
------------------------------------------- (case)
case t of inl x₁ => t₁ | inr x₂ => t₂ ⟶
case t' of inl x₁ => t₁ | inr x₂ => t₂
----------------------------------------------- (caseInl)
case (inl τ₂ v₁) of inl x₁ => t₁ | inr x₂ => t₂
⟶ [x₁ := v₁]t₁
----------------------------------------------- (caseInr)
case (inr τ₁ v₂) of inl x₁ => t₁ | inr x₂ => t₂
⟶ [x₂ := v₂]t₂
Typing:
Γ ⊢ t₁ ⦂ τ₁
---------------------------- (inl)
Γ ⊢ inl τ₂ t₁ ⦂ τ₁ + τ₂
Γ ⊢ t₂ ⦂ τ₂
--------------------------- (inr)
Γ ⊢ inr τ₁ t₂ ⦂ τ₁ + τ₂
Γ ⊢ t ⦂ τ₁ + τ₂
x₁ ↦ τ₁; Γ ⊢ t₁ ⦂ τ₃
x₂ ↦ τ₂; Γ ⊢ t₂ ⦂ τ₃
---------------------------------------------------- (case)
Γ ⊢ case t of inl x₁ => t₁ | inr x₂ => t₂ ⦂ τ₃
We use the type annotations on inl and inr to make the typing
relation deterministic (each term has at most one type), as we
did for functions.
Without this extra information, the typing rule inl, for
example, would have to say that, once we have shown that t₁ is
an element of type τ₁, we can derive that inl t₁ is an element
of τ₁ + τ₂ for any type τ₂. For example, we could derive both
inl 5 : Nat + Natand inl 5 : Nat + Bool (and infinitely many other types).
This peculiarity (technically, a failure of uniqueness of types) would mean t
hat we cannot build a typechecking algorithm simply by "reading the rules from bottom to
top" as we could for all the other features seen so far.
There are various ways to deal with this difficulty. One simple one -- which we've adopted here -- forces the programmer to explicitly annotate the "other side" of a sum type when performing an injection. This is a bit heavy for programmers (so real languages adopt other solutions), but it is easy to understand and formalize.
What does the following term step to (in one step)?
let F = λX : Nat + Bool.
case X of
inl N => N + 3
| inr B => 0 in
F (inl Bool 4)
(A) (λX : Nat + Bool.
case X of
inl N => N + 3
| inr B => 0
) (inl Bool 4)
(B) 7
(C) case inl Bool 4 of
inl N => N + 3
| inr B => 0
(D) F (inl Bool 4)
What about this one?
(λX : Nat + Bool.
case X of
inl N => N + 3
| inr B => 0
) (inl Bool 4)
(A) 7
(B) case inl Bool 4 of
inl N => N + 3
| inr B => 0
(C) 4 + 3
What about this one?
case inl Bool 4 of
inl N => N + 3
| inr B => 0
(A) 4 + 3
(B) 7
(C) 0
7.1.5. Lists
The typing features we have seen can be classified into
base types like Bool, and type constructors like → and
× that build new types from old ones. Another useful type
constructor is List. For every type τ, the type List τ
describes finite-length lists whose elements are drawn from τ.
In principle, we could encode lists using pairs, sums, unit, and recursive types. But giving semantics to recursive types is non-trivial. Instead, we'll just discuss the special case of lists directly.
Below we give the syntax, semantics, and typing rules for lists.
Except for the fact that explicit type annotations are mandatory
on nil and cannot appear on cons, these lists are essentially
identical to those we built in Rocq. We use case, rather than
head and tail operators, to destruct lists, to avoid dealing
with questions like "what is the head of the ∅ list?"
For example, here is a function that calculates the sum of the first two elements of a list of numbers:
λ X:List Nat. case X of nil => 0 | A :: Xs' => case Xs' of nil => A | B :: Xs'' => A + B
Syntax:
t ::= Terms
| ...
| nil τ ∅ list
| t₁ :: t₂ cons
| case t₁ of case analysis
nil => t₂
| xh::xt => t₃
v ::= Values
| ...
| nil τ nil value
| v₁ :: v₂ cons value
τ ::= Types
| ...
| List τ list of τs
Reduction:
t₁ ⟶ t₁'
-------------------------- (cons₁)
t₁ :: t₂ ⟶ t₁' :: t₂
t₂ ⟶ t₂'
-------------------------- (cons₂)
v₁ :: t₂ ⟶ v₁ :: t₂'
t₁ ⟶ t₁'
------------------------------------------- (listCase₁)
(case t₁ of nil => t₂ | xh :: xt => t₃) ⟶
(case t₁' of nil => t₂ | xh :: xt => t₃)
------------------------------------------ (listCaseNil)
(case nil τ₁ of nil => t₂ | xh :: xt => t₃)
⟶ t₂
------------------------------------------- (listCaseCons)
(case (vh :: vt) of nil => t₂ | xh :: xt => t₃)
⟶ [xh:=vh][xt:=vt] t₃
Typing:
---------------------------- (nil)
Γ ⊢ nil τ₁ ⦂ List τ₁
Γ ⊢ t₁ ⦂ τ₁ Γ ⊢ t₂ ⦂ List τ₁
------------------------------------------------- (cons)
Γ ⊢ t₁ :: t₂ ⦂ List τ₁
Γ ⊢ t₁ ⦂ List τ₁
Γ ⊢ t₂ ⦂ τ₂
(xh ↦ τ₁; xt ↦ List τ₁; Γ) ⊢ t₃ ⦂ τ₂
---------------------------------------------------- (listCase)
Γ ⊢ (case t₁ of nil => t₂ | xh :: xt => t₃) ⦂ τ₂
7.1.6. General Recursion
Another facility found in most programming languages (including Lean) is the ability to define recursive functions. For example, we would like to be able to define and use the factorial function like this:
let Fact = λX:Nat.
if X=0 then 1 else X * (Fact (pred X))) in
Fact 3.
Note that the right-hand side of this binder mentions Fact, the
variable being bound - something that is not allowed according
to the way we defined let above.
(The body of a let is typechecked in the same context as the
let itself, which means that the recursive occurrence of Fact in the
body will not have a type in the context when it is looked up by the
var rule.)
Changing the let rule to handle "recursive definitions"
like this is possible, but it requires some extra effort -- e.g.,
passing around an extra "environment" of recursive function
definitions in the definition of the step relation. We're going
to take a simpler path here.
Here is another way of presenting recursive functions that is
a bit more verbose but equally powerful and much more straightforward
to formalize: instead of writing recursive definitions, we will define
a fixed-point operator called fix that performs the "unfolding"
of the recursive definition in the right-hand side as needed, during
reduction.
For example, instead of
Fact = λX:Nat.
if X=0 then 1 else X * (Fact (pred X)))
we will write:
Fact =
fix
(λF:Nat → Nat.
λX:Nat.
if X=0 then 1 else X * (F (pred X)))
We can derive the latter from the former as follows:
-
In the right-hand side of the definition of
Fact, replace recursive references toFactby a fresh variableF. -
Add an abstraction binding
Fat the front, with an appropriate type annotation. (Since we are usingFin place ofFact, which had typeNat→Nat, we should requireFto have the same type.) The new abstraction has type(Nat→Nat) → (Nat→Nat). -
Apply
fixto this abstraction. This application has typeNat→Nat. -
Use all of this as the right-hand side of an ordinary
let-binding forFact.
For the mathematically inclined,
the intuition here is that the higher-order function F
passed to fix is a generator for the Fact function: if F
is applied to a function that "approximates" the desired behavior
of Fact up to some number n (that is, a function that returns
correct results on inputs less than or equal to n but we don't
care what it does on inputs greater than n), then F returns a
slightly better approximation to Fact -- a function that returns
correct results for inputs up to n+1. Applying fix to this
generator returns its fixed point, which is a function that
gives the desired behavior for all inputs n.
(The term "fixed point" is used here in exactly the same sense as
in ordinary mathematics, where a fixed point of a function f is
an input x such that f(x) = x. Here, a fixed point of a
function F of type (Nat→Nat)→(Nat→Nat) is a function f of
type Nat→Nat such that F f behaves the same as f.)
Syntax:
t ::= Terms
| ...
| fix t₁ fixed-point operator
Reduction:
t₁ ⟶ t₁'
------------------ (fix₁)
fix t₁ ⟶ fix t₁'
-------------------------------------------- (fixAbs)
fix (λxf:τ₁.t₁) ⟶ [xf:=fix (λxf:τ₁.t₁)] t₁
Typing:
Γ ⊢ t₁ ⦂ τ₁ → τ₁
------------------ (fix)
Γ ⊢ fix t₁ ⦂ τ₁
Let's see how fixAbs works by reducing Fact 3 = fix F 3, where
F = (λF. λX. if X=0 then 1 else X * (F (pred X)))
(type annotations are omitted for brevity).
fix F 3
⟶ fixAbs + app₁
(λX. if X=0 then 1 else X * (fix F (pred X))) 3
⟶ appAbs
if 3=0 then 1 else 3 * (fix F (pred 3))
⟶ if0Nonzero
3 * (fix F (pred 3))
⟶ fixAbs + mult₂ + app₁
3 * ((λX. if X=0 then 1 else X * (fix F (pred X))) (pred 3))
⟶ predNat + mult₂ + app₂
3 * ((λX. if X=0 then 1 else X * (fix F (pred X))) 2)
⟶ appAbs + mult₂
3 * (if 2=0 then 1 else 2 * (fix F (pred 2)))
⟶ if0Nonzero + mult₂
3 * (2 * (fix F (pred 2)))
⟶ fixAbs + 2 × mult₂ + app₁
3 * (2 * ((λX. if X=0 then 1 else X * (fix F (pred X))) (pred 2)))
⟶ predNat + 2 x mult₂ + app₂
3 * (2 * ((λX. if X=0 then 1 else X * (fix F (pred X))) 1))
⟶ appAbs + 2 x mult₂
3 * (2 * (if 1=0 then 1 else 1 * (fix F (pred 1))))
⟶ if0Nonzero + 2 x mult₂
3 * (2 * (1 * (fix F (pred 1))))
⟶ fixAbs + 3 x mult₂ + app₁
3 * (2 * (1 * ((λX. if X=0 then 1 else X * (fix F (pred X))) (pred 1))))
⟶ predNat + 3 × mult₂ + app₂
3 * (2 * (1 * ((λX. if X=0 then 1 else X * (fix F (pred X))) 0)))
⟶ appAbs + 3 × mult₂
3 * (2 * (1 * (if 0=0 then 1 else 0 * (fix F (pred 0)))))
⟶ if0Zero + 3 x mult₂
3 * (2 * (1 * 1))
⟶ multNats + 2 x mult₂
3 * (2 * 1)
⟶ multNats + mult₂
3 * 2
⟶ multNats
6
The simply typed lambda-calculus with fixed points is a famous and extensively studied system. It is often called PCF because it is a simple language of "partial computable functions".
Is this a well-typed Stlc term? What does it evaluate to?
fix (λF: Nat→Nat. λX:Nat. F X) 0
(A) no
(B) yes, diverges
(C) yes, [42]
(D) yes, [0]
Which of the following are (intuitively) true for Stlc + fixpoints.
(A) deterministic
(B) progress
(C) preservation
(D) normalizing (i.e. every well-typed term reduces to a normal form)
Translate this informal recursive definition into one using fix:
Halve =
λX:Nat.
if X=0 then 0
else if (pred X)=0 then 0
else 1 + (Halve (pred (pred X)))
Halve =
fix
(λF:Nat→Nat.
λX:Nat.
if X=0 then 0
else if (pred X)=0 then 0
else 1 + (F (pred (pred X))))
Write down the sequence of steps that the term Fact 1 goes
through to reduce to a normal form (assuming the usual reduction
rules for arithmetic operations.
Fact 1
= fix (λF:Nat→Nat. λX:Nat. if X=0 then 1 else X * (F (pred X))) 1
⟶ (λX: Nat, if X = 0 then 1 else X * (Fact (pred X))) 1
⟶ if 1 = 0 then 1 else 1 * (Fact (pred 1))
⟶ 1 * (Fact (pred 1))
⟶ 1 * ((λX:Nat. if X=0 then 1 else X * (Fact (pred X))) (pred 1))
⟶ 1 * ((λX:Nat. if X=0 then 1 else X * (Fact (pred X))) 0)
⟶ 1 * (if 0=0 then 1 else 0 * (Fact (pred 0)))
⟶ 1 * 1
⟶ 1
Also see the solution to exercise fact_example below.
The ability to form the fixed point of a function of type τ→τ
for any τ has some surprising consequences. In particular, it
implies that every type is inhabited by some term. To see this,
observe that, for every type τ, we can define the term:
fix (λx:τ. x)
By fix and abs, this term has type τ. By fixAbs
it reduces to itself, over and over again. Thus it is a
diverging element of τ.
More usefully, here's an example using fix to define a
two-argument recursive function:
Equal =
fix
(λEq:Nat→Nat→Bool.
λM:Nat. λN:Nat.
if M=0 then iszero N
else if N=0 then false
else Eq (pred M) (pred N))
And finally, here is an example where fix is used to define a
pair of recursive functions (illustrating the fact that the type
τ₁ in the rule fix need not be a function type):
let EvenOdd =
fix
(λEo: ((Nat → Nat) * (Nat → Nat)).
(λN:Nat. if0 N then 1 else (snd Eo (pred N)),
λN:Nat. if0 N then 0 else (fst Eo (pred N)))) in
let Even = fst EvenOdd in
let Odd = snd EvenOdd in
(Even 3, Even 4)}
7.2. Records
As a final example of a basic extension of the STLC, let's look briefly at how to define records and their types. Intuitively, records can be obtained from pairs by two straightforward generalizations: they are n-ary (rather than just binary) and their fields are accessed by label (rather than position).
Syntax:
t ::= Terms
| ...
| {i₁=t₁, ..., iₙ=tₙ} record
| t.i projection
v ::= Values
| ...
| {i₁=v₁, ..., iₙ=vₙ} record value
τ ::= Types
| ...
| {i₁:τ₁, ..., iₙ:τₙ} record type
The generalization from products should be pretty obvious. But
it's worth noticing the ways in which what we've actually written is
even more informal than the informal syntax we've used in previous
sections and chapters: we've used "..." in several places to mean "any number of these,"
and we've omitted explicit mention of the usual
side condition that the labels of a record should not contain any repetitions.
Reduction:
ti ⟶ ti'
------------------------------------ (rcd)
{i₁=v₁, ..., im=vm, in=ti , ...}
⟶ {i₁=v₁, ..., im=vm, in=ti', ...}
t ⟶ t'
-------------- (proj₁)
t.i ⟶ t'.i
------------------------- (projRcd)
{..., i=vi, ...}.i ⟶ vi
Again, these rules are a bit informal. For example, the first rule
is intended to be read "if ti is the leftmost field that is not a
value and if ti steps to ti', then the whole record steps..."
In the last rule, the intention is that there should be only one
field called i, and that all the other fields must contain values.
The typing rules are also simple:
Γ ⊢ t₁ ⦂ τ₁ ... Γ ⊢ tₙ ⦂ τₙ
----------------------------------------------------- (rcd)
Γ ⊢ {i₁=t₁, ..., iₙ=tₙ} ⦂ {i₁:τ₁, ..., iₙ:τₙ}
Γ ⊢ t ⦂ {..., i:τᵢ, ...}
--------------------------------- (proj)
Γ ⊢ t.i ⦂ τᵢ
There are several ways to approach formalizing the above definitions.
-
We can directly formalize the syntactic forms and inference rules, staying as close as possible to the form we've given them above. This is conceptually straightforward, and it's probably what we'd want to do if we were building a real compiler (in particular, it will allow us to print error messages in the form that programmers will find easy to understand). But the formal versions of the rules will not be very pretty or easy to work with, because all the
...s above will have to be replaced with explicit quantifications or comprehensions. For this reason, records are not included in the extended exercise at the end of this chapter. (It is still useful to discuss them informally here because they will help motivate the addition of subtyping to the type system when we get to the Sub chapter.) -
Alternatively, we could look for a smoother way of presenting records -- for example, a binary presentation with one constructor for the ∅ record and another constructor for adding a single field to an existing record, instead of a single monolithic constructor that builds a whole record at once. This is the right way to go if we are primarily interested in studying the metatheory of the calculi with records, since it leads to clean and elegant definitions and proofs.
-
Finally, if we like, we can avoid formalizing records altogether, by stipulating that record notations are just informal shorthands for more complex expressions involving pairs and product types. We sketch this approach in the next section.
Let's see how records can be encoded using just pairs and
unit. (This clever encoding, as well as the observation that it
also extends to systems with subtyping, is due to Luca Cardelli.)
First, observe that we can encode arbitrary-size tuples using
nested pairs and the unit value. To avoid overloading the pair
notation (t₁,t₂), we'll use curly braces without labels to write
down tuples, so {} is the ∅ tuple, {5} is a singleton
tuple, {5,6}]is a 2-tuple (morally the same as a pair),
{5,6,7} is a triple, etc.
{} ⟶ unit
{t₁, t₂, ..., tn} ⟶ (t₁, trest)
where {t₂, ..., tn} ⟶ trest
Similarly, we can encode tuple types using nested product types:
{} ⟶ Unit
{τ₁, τ₂, ..., τₙ} ⟶ τ₁ × τrest
where {τ₂, ..., τₙ} ⟶ τrest
The operation of projecting a field from a tuple can be encoded using a sequence of second projections followed by a first projection:
t.0 ⟶ fst t
t.(n+1) ⟶ (snd t).n
Next, suppose that there is some total ordering on record labels, so that we can associate each label with a unique natural number. This number is called the position of the label. For example, we might assign positions like this:
LABEL POSITION
a 0
b 1
c 2
... ...
bar 1395
... ...
foo 4460
... ...
We use these positions to encode record values as tuples (i.e., as nested pairs) by sorting the fields according to their positions. For example:
{a=5,b=6} ⟶ {5,6}
{a=5,c=7} ⟶ {5,unit,7}
{c=7,a=5} ⟶ {5,unit,7}
{c=5,b=3} ⟶ {unit,3,5}
{f=8,c=5,a=7} ⟶ {7,unit,5,unit,unit,8}
{f=8,c=5} ⟶ {unit,unit,5,unit,unit,8}
Note that each field appears in the position associated with its
label, that the size of the tuple is determined by the label with
the highest position, and that we fill in unused positions with
unit.
We do exactly the same thing with record types:
{a:Nat,b:Nat} ⟶ {Nat,Nat}
{c:Nat,a:Nat} ⟶ {Nat,Unit,Nat}
{f:Nat,c:Nat} ⟶ {Unit,Unit,Nat,Unit,Unit,Nat}
Finally, record projection is encoded as a tuple projection from the appropriate position:
t.l ⟶ t.(position of l)
It is not hard to check that all the typing rules for the original "direct" presentation of records are validated by this encoding. (The reduction rules are "almost validated" -- not quite, because the encoding reorders fields.)
Of course, this encoding will not be very efficient if we
happen to use a record with label foo! But things are not
actually as bad as they might seem: for example, if we assume that
our compiler can see the whole program at the same time, we can
choose the numbering of labels so that we assign small positions
to the most frequently used labels. Indeed, there are industrial
compilers that essentially do this!
Just as products can be generalized to records, sums can be
generalized to n-ary labeled types called variants. Instead of
τ₁+τ₂, we can write something like <l₁:τ₁,l₂:τ₂,...lₙ:τₙ>
where l₁,l₂,... are field labels which are used both to build
instances and as case arm labels.
These n-ary variants give us almost enough mechanism to build arbitrary inductive data types like lists and trees from scratch -- the only thing missing is a way to allow recursion in type definitions. We won't cover this here, but detailed treatments can be found in many textbooks -- e.g., Types and Programming Languages (Pierce, 2002)Benjamin C. Pierce (2002). “Types and Programming Languages”. MIT Press. ..
7.2.1. Exercise: Formalizing the Extensions
In this series of exercises, you will formalize some of the extensions described in this chapter. We've provided the necessary additions to the syntax of terms and types, and we've included a few examples that you can test your definitions with to make sure they are working as expected. You'll fill in the rest of the definitions and extend all the proofs accordingly.
To get you started, we've provided implementations for:
-
numbers
-
sums
-
lists
-
unit
You need to complete the implementations for:
-
pairs
-
let (which involves binding)
-
fix
A good strategy is to work on the extensions one at a time (first pairs, then let, then fix), in separate passes, rather than trying to do all three at once in a single pass. For each definition or proof, begin by reading carefully through the parts that are provided for you, referring to the text in the Stlc chapter for high-level intuitions and the embedded comments for detailed mechanics.
Syntax:
namespace StlcExtended
open scoped MyGetElem
inductive Ty : Type where
| arrow : Ty → Ty → Ty
| nat : Ty
| sum : Ty → Ty → Ty
| list : Ty → Ty
| unit : Ty
| prod : Ty → Ty → Ty
inductive Tm : Type where
-- pure STLC
| var : String → Tm
| app : Tm → Tm → Tm
| abs : String → Ty → Tm → Tm
-- numbers
| const: Nat → Tm
| succ : Tm → Tm
| pred : Tm → Tm
| mult : Tm → Tm → Tm
| ite0 : Tm → Tm → Tm → Tm
-- sums
| sumInl : Ty → Tm → Tm
| sumInr : Ty → Tm → Tm
| sumCase : Tm → String → Tm → String → Tm → Tm
-- i.e., `case t of inl x₁ => t₁ | inr x₂ => t₂`
-- lists
| listNil : Ty → Tm
| listCons : Tm → Tm → Tm
| listCase : Tm → Tm → String → String → Tm → Tm
-- i.e., [case t₁ of | nil => t₂ | x::y => t₃]
-- unit
| unit : Tm
-- You are going to be working on the following extensions:
-- pairs
| pair : Tm → Tm → Tm
| fst : Tm → Tm
| snd : Tm → Tm
-- let
| letIn : String → Tm → Tm → Tm
-- i.e., [let x = t₁ in t₂]
-- fix
| fix : Tm → Tm
Note that, for brevity, we've omitted booleans and instead
provided a single if0 form combining a zero test and a
conditional. That is, instead of writing
if x = 0 then ... else ...
we'll write this:
if0 x then ... else ...
As in Stlc, terms, types, contexts, and typing judgments use
<{ … }> brackets. Capital Latin identifiers are object-language names;
lowercase and Greek identifiers refer directly to in-scope Lean variables;
arbitrary Lean expressions require ~ antiquotation.
Notation
scoped syntax:50 stlcTy:51 " × " stlcTy:50 : stlcTy
scoped syntax:50 stlcTy:51 " + " stlcTy:50 : stlcTy
scoped syntax:51 " [ " stlcTy:50 " ] " : stlcTy
scoped syntax:max num : stlcTm
scoped syntax:60 stlcTm:60 " * " stlcTm:61 : stlcTm
scoped syntax:50 "if0 " stlcTm:51 " then " stlcTm:50 " else " stlcTm:50 : stlcTm
scoped syntax:60 " inr " stlcTy:60 ppSpace stlcTm:60 : stlcTm
scoped syntax:60 " inl " stlcTy:60 ppSpace stlcTm:60 : stlcTm
scoped syntax:50 "case " stlcTm:50 " of " "inl" stlcVar " => " stlcTm:50 " | "
"inr" stlcVar " => " stlcTm:50 : stlcTm
scoped syntax:60 " nil " stlcTy:60 : stlcTm
scoped syntax:60 stlcTm:61 " :: " stlcTm:60 : stlcTm
scoped syntax:50 "case " stlcTm:50 " of " "nil" " => " stlcTm:50 " | "
stlcVar " :: " stlcVar " => " stlcTm:50 : stlcTm
scoped syntax:max " ( " stlcTm:60 " , " stlcTm:60 " ) " : stlcTm
scoped syntax:50 "let " stlcVar " = " stlcTm:50 " in " stlcTm:50 : stlcTm
namespace Elab
open StlcCommon
open Lean Meta Elab Term
def language : Language where
tyType := ``Ty
tmType := ``Tm
arrowCtor := ``Ty.arrow
varCtor := ``Tm.var
appCtor := ``Tm.app
absCtor := ``Tm.abs
-- defined later
subst := `StlcExtended.subst
hasType := `StlcExtended.HasType
def extendedTyHandler : TyElabHandler :=
fun recur k T => do
match T with
| `(stlcTy| Nat) =>
return mkConst ``Ty.nat
| `(stlcTy| Unit) =>
return mkConst ``Ty.unit
| `(stlcTy| $T₁:stlcTy + $T₂:stlcTy) => do
let T₁ ← recur T₁
let T₂ ← recur T₂
return mkApp2 (mkConst ``Ty.sum) T₁ T₂
| `(stlcTy| [$T:stlcTy]) => do
let T ← recur T
return mkApp (mkConst ``Ty.list) T
| `(stlcTy| $T₁:stlcTy × $T₂:stlcTy) => do
let T₁ ← recur T₁
let T₂ ← recur T₂
return mkApp2 (mkConst ``Ty.prod) T₁ T₂
| _ => k T
def tyHandlers : TyElabHandler :=
extendedTyHandler.orElse (commonTyHandler language)
partial def elabTy : TyElab :=
tyHandlers elabTy <| unsupportedTy language
def extendedTmHandler : TmElabHandler :=
fun recur k Γ free t => do
match t with
| `(stlcTm| $n:num) => do
return (mkApp (mkConst ``Tm.const) (mkNatLit n.getNat), free )
| `(stlcTm| Nat) => do
throwError "`Nat` is not a valid term."
| `(stlcTm| succ $t:stlcTm) => do
let (t, free) ← recur Γ free t
return (mkApp (mkConst ``Tm.succ) t, free)
| `(stlcTm| pred $t:stlcTm) => do
let (t, free) ← recur Γ free t
return (mkApp (mkConst ``Tm.pred) t, free)
| `(stlcTm| $t₁:stlcTm * $t₂:stlcTm) => do
let (t₁, free) ← recur Γ free t₁
let (t₂, free) ← recur Γ free t₂
return (mkApp2 (mkConst ``Tm.mult) t₁ t₂, free)
| `(stlcTm| if0 $c:stlcTm then $t:stlcTm else $e:stlcTm) => do
let (c, free) ← recur Γ free c
let (t, free) ← recur Γ free t
let (e, free) ← recur Γ free e
return (mkApp3 (mkConst ``Tm.ite0) c t e, free)
| `(stlcTm| inl $T:stlcTy $t:stlcTm) => do
let T ← elabTy T
let (t, free) ← recur Γ free t
return (mkApp2 (mkConst ``Tm.sumInl) T t, free)
| `(stlcTm| inr $T:stlcTy $t:stlcTm) => do
let T ← elabTy T
let (t, free) ← recur Γ free t
return (mkApp2 (mkConst ``Tm.sumInr) T t, free)
| `(stlcTm|
case $t:stlcTm of
inl $x₁:stlcVar => $t₁:stlcTm |
inr $x₂:stlcVar => $t₂:stlcTm) => do
let (t, free) ← recur Γ free t
-- The branches start from the same lexical Γ
-- Only `free` is threaded from branch 1 into branch 2
let (x₁, Γ₁) ← elabStlcBinder language Γ x₁
let (t₁, free) ← recur Γ₁ free t₁
let (x₂, Γ₂) ← elabStlcBinder language Γ x₂
let (t₂, free) ← recur Γ₂ free t₂
return (mkAppN (mkConst ``Tm.sumCase) #[t, x₁, t₁, x₂, t₂], free)
| `(stlcTm| nil $T:stlcTy) => do
let T ← elabTy T
return (mkApp (mkConst ``Tm.listNil) T, free)
| `(stlcTm| $t₁:stlcTm :: $t₂:stlcTm) => do
let (t₁, free) ← recur Γ free t₁
let (t₂, free) ← recur Γ free t₂
return (mkApp2 (mkConst ``Tm.listCons) t₁ t₂, free)
| `(stlcTm|
case $t₁:stlcTm of
nil => $t₂:stlcTm |
$x:stlcVar :: $xs:stlcVar => $t₃:stlcTm) => do
let (t₁, free) ← recur Γ free t₁
-- nil branch has no binders
let (t₂, free) ← recur Γ free t₂
-- cons branch has two binders
let (x, Γ) ← elabStlcBinder language Γ x
let (xs, Γ) ← elabStlcBinder language Γ xs
let (t₃, free) ← recur Γ free t₃
return (mkAppN (mkConst ``Tm.listCase) #[t₁, t₂, x, xs, t₃], free)
| `(stlcTm| Unit) => do
throwError "`Unit` is not a valid term."
| `(stlcTm| unit) => do
return (mkConst ``Tm.unit, free)
| `(stlcTm| ($t₁:stlcTm, $t₂:stlcTm)) => do
let (t₁, free) ← recur Γ free t₁
let (t₂, free) ← recur Γ free t₂
return (mkApp2 (mkConst ``Tm.pair) t₁ t₂, free)
| `(stlcTm| fst $t:stlcTm) => do
let (t, free) ← recur Γ free t
return (mkApp (mkConst ``Tm.fst) t, free)
| `(stlcTm| snd $t:stlcTm) => do
let (t, free) ← recur Γ free t
return (mkApp (mkConst ``Tm.snd) t, free)
| `(stlcTm|
let $x:stlcVar = $t₁:stlcTm
in $t₂:stlcTm) => do
-- x is NOT in scope in t₁
let (t₁, free) ← recur Γ free t₁
-- but in scope in t₂
let (x, Γ₂) ← elabStlcBinder language Γ x
let (t₂, free) ← recur Γ₂ free t₂
return (mkApp3 (mkConst ``Tm.letIn) x t₁ t₂, free)
| `(stlcTm| fix $t:stlcTm) => do
let (t, free) ← recur Γ free t
return (mkApp (mkConst ``Tm.fix) t, free)
| _ => k Γ free t
def tmHandlers : TmElabHandler :=
extendedTmHandler.orElse (commonTmHandler language elabTy)
partial def elabTm : TmElab :=
tmHandlers elabTm unsupportedTm
def elabCtx : CtxElab := elabCtxCommon language elabTy
@[scoped term_elab StlcCommon.bracket]
def elabBracket : TermElab :=
fun stx expectedType? => do
let `(<{ $q:stlcQuoted }>) := stx
| throwUnsupportedSyntax
elabQuoted language elabTy elabTm elabCtx q expectedType?
end Elab
open scoped Elab
namespace Delab
open StlcCommon Elab Delab
open Lean PrettyPrinter Delaborator
@[app_unexpander Ty.nat]
private def Ty.unexpandNat : Unexpander
| stx => do
let Nat := mkObjectIdentFrom stx "Nat"
let T ← `(stlcTy| $Nat:ident)
`(<{ $T:stlcTy }>)
@[app_unexpander Ty.unit]
private def Ty.unexpandUnit : Unexpander
| stx => do
let Unit := mkObjectIdentFrom stx "Unit"
let T ← `(stlcTy| $Unit:ident)
`(<{ $T:stlcTy }>)
@[app_unexpander Ty.arrow]
private def Ty.unexpandArrow : Unexpander := Delab.unexpandArrow
@[app_unexpander Ty.sum]
private def Ty.unexpandSum : Unexpander
| `($_ $T₁ $T₂) => do
let T₁' := getTy T₁
let T₂' := getTy T₂
`(<{ $T₁':stlcTy + $T₂':stlcTy }>)
| _ => throw ()
@[app_unexpander Ty.list]
private def Ty.unexpandList : Unexpander
| `($_ $T) => do
let T' := getTy T
`(<{ [$T':stlcTy] }>)
| _ => throw ()
@[app_unexpander Ty.prod]
private def Ty.unexpandProd : Unexpander
| `($_ $T₁ $T₂) => do
let T₁' := getTy T₁
let T₂' := getTy T₂
`(<{ $T₁':stlcTy × $T₂':stlcTy }>)
| _ => throw ()
private def reservedNames : String → Bool
| "Nat" | "Unit" | "succ" | "pred"
| "if0" | "inl" | "inr" | "nil"
| "unit" | "fst" | "snd" | "let"
| "fix" | "case" => true
| _ => false
@[app_unexpander Tm.var]
private def Tm.unexpandVar : Unexpander := Delab.unexpandVar reservedNames ``Tm.var
@[app_delab Tm.var]
private def Tm.delabVar : Delab := Delab.delabVar ``Tm.var
@[app_unexpander Tm.app]
private def Tm.unexpandApp : Unexpander := Delab.unexpandApp
@[app_unexpander Tm.abs]
private def Tm.unexpandAbs : Unexpander := Delab.unexpandAbs
@[app_unexpander Tm.const]
private def Tm.unexpandConst : Unexpander
| `($_ $n:num) => `(<{ $n:num }>)
| _ => throw ()
@[app_unexpander Tm.succ]
private def Tm.unexpandSucc : Unexpander
| stx@`($_ $t) => do
let succ := mkObjectIdentFrom stx "succ"
let t' := getTm t
`(<{ $succ:ident $t':stlcTm }>)
| _ => throw ()
@[app_unexpander Tm.pred]
private def Tm.unexpandPred : Unexpander
| stx@`($_ $t) => do
let pred := mkObjectIdentFrom stx "pred"
let t' := getTm t
`(<{ $pred:ident $t':stlcTm }>)
| _ => throw ()
@[app_unexpander Tm.mult]
private def Tm.unexpandMult : Unexpander
| `($_ $t₁ $t₂) => do
let t₁' := getTm t₁
let t₂' := getTm t₂
`(<{ $t₁':stlcTm * $t₂':stlcTm }>)
| _ => throw ()
@[app_unexpander Tm.ite0]
private def Tm.unexpandIte0 : Unexpander
| `($_ $c $t $e) => do
let c' := getTm c
let t' := getTm t
let e' := getTm e
`(<{ if0 $c':stlcTm then $t':stlcTm else $e':stlcTm }>)
| _ => throw ()
@[app_unexpander Tm.sumInl]
private def Tm.unexpandSumInl : Unexpander
| `($_ $T $t) => do
let T' := getTy T
let t' := getTm t
`(<{ inl $T':stlcTy $t':stlcTm }>)
| _ => throw ()
@[app_unexpander Tm.sumInr]
private def Tm.unexpandSumInr : Unexpander
| `($_ $T $t) => do
let T' := getTy T
let t' := getTm t
`(<{ inr $T':stlcTy $t':stlcTm }>)
| _ => throw ()
@[app_unexpander Tm.sumCase]
private def Tm.unexpandSumCase : Unexpander
| `($_ $t $x₁ $t₁ $x₂ $t₂) => do
let t' := getTm t
let x₁' := getVar x₁
let t₁' := getTm t₁
let x₂' := getVar x₂
let t₂' := getTm t₂
`(<{
case $t':stlcTm of
inl $x₁':stlcVar => $t₁':stlcTm |
inr $x₂':stlcVar => $t₂':stlcTm
}>)
| _ => throw ()
@[app_unexpander Tm.listNil]
private def Tm.unexpandListNil : Unexpander
| `($_ $T) => do
let T' := getTy T
`(<{ nil $T':stlcTy }>)
| _ => throw ()
@[app_unexpander Tm.listCons]
private def Tm.unexpandListCons : Unexpander
| `($_ $t₁ $t₂) => do
let t₁' := getTm t₁
let t₂' := getTm t₂
`(<{ $t₁':stlcTm :: $t₂':stlcTm }>)
| _ => throw ()
@[app_unexpander Tm.listCase]
private def Tm.unexpandListCase : Unexpander
| `($_ $t₁ $t₂ $x $xs $t₃) => do
let t₁' := getTm t₁
let t₂' := getTm t₂
let x' := getVar x
let xs' := getVar xs
let t₃' := getTm t₃
`(<{
case $t₁':stlcTm of
nil => $t₂':stlcTm |
$x':stlcVar :: $xs':stlcVar => $t₃':stlcTm
}>)
| _ => throw ()
@[app_unexpander Tm.unit]
private def Tm.unexpandUnit : Unexpander
| stx => do
let unit := mkObjectIdentFrom stx "unit"
let t ← `(stlcTm| $unit:ident)
`(<{ $t:stlcTm }>)
@[app_unexpander Tm.pair]
private def Tm.unexpandPair : Unexpander
| `($_ $t₁ $t₂) => do
let t₁' := getTm t₁
let t₂' := getTm t₂
`(<{ ($t₁':stlcTm, $t₂':stlcTm) }>)
| _ => throw ()
@[app_unexpander Tm.fst]
private def Tm.unexpandFst : Unexpander
| stx@`($_ $t) => do
let fst := mkObjectIdentFrom stx "fst"
let t' := getTm t
`(<{ $fst:ident $t':stlcTm }>)
| _ => throw ()
@[app_unexpander Tm.snd]
private def Tm.unexpandSnd : Unexpander
| stx@`($_ $t) => do
let snd := mkObjectIdentFrom stx "snd"
let t' := getTm t
`(<{ $snd:ident $t':stlcTm }>)
| _ =>
throw ()
@[app_unexpander Tm.letIn]
private def Tm.unexpandLetIn : Unexpander
| `($_ $x $t₁ $t₂) => do
let x' := getVar x
let t₁' := getTm t₁
let t₂' := getTm t₂
`(<{
let $x':stlcVar =
$t₁':stlcTm
in
$t₂':stlcTm
}>)
| _ => throw ()
@[app_unexpander Tm.fix]
private def Tm.unexpandFix : Unexpander
| stx@`($_ $t) => do
let fix := mkObjectIdentFrom stx "fix"
let t' := getTm t
`(<{ $fix:ident $t':stlcTm }>)
| _ => throw ()
end Delab
def subst (x : String) (s : Tm) (t : Tm) : Tm :=
match t with
-- pure STLC
| .var y =>
if x = y then s else t
| .abs y τ t₁ =>
if x = y then t else <{ λ y : τ . [x := s] t₁ }>
| .app t₁ t₂ =>
<{ ([x := s] t₁) ([x := s] t₂) }>
-- numbers
| .const _ =>
t
| .succ t₁ =>
<{ succ ([x := s] t₁) }>
| .pred t₁ =>
<{ pred ([x := s] t₁) }>
| .mult t₁ t₂ =>
<{ ([x := s] t₁) * ([x := s] t₂) }>
| .ite0 t₁ t₂ t₃ =>
<{
if0 [x := s] t₁
then [x := s] t₂
else [x := s] t₃
}>
-- sums
| .sumInl τ₂ t₁ =>
<{ inl τ₂ ([x := s] t₁) }>
| .sumInr τ₂ t₁ =>
<{ inr τ₂ ([x := s] t₁) }>
| .sumCase t x₁ t₁ x₂ t₂ =>
let t₁ := if x = x₁ then t₁ else <{ [x := s] t₁ }>
let t₂ := if x = x₂ then t₂ else <{ [x := s] t₂ }>
<{
case ([x := s] t) of
inl x₁ => t₁ |
inr x₂ => t₂
}>
-- lists
| .listNil _ => t
| .listCons t₁ t₂ => <{ ([x := s] t₁) :: ([x := s] t₂) }>
| .listCase t₁ t₂ x₁ x₂ t₃ =>
let t₃ := if x = x₁ || x = x₂ then t₃ else <{ [x := s] t₃ }>
<{
case ([x := s] t₁) of
nil => [x := s] t₂ |
x₁ :: x₂ => t₃
}>
-- unit
| .unit => <{ unit }>
-- Complete the following cases.
-- pairs
| .pair t₁ t₂ =>
solution!(<{ (([x := s] t₁), ([x := s] t₂)) }>)
| .fst t₁ =>
solution!(<{ fst ([x := s] t₁) }>)
| .snd t₁ =>
solution!(<{ snd ([x := s] t₁) }>)
-- let
| .letIn y t₁ t₂ => solution!(
let t₂ := if x = y then t₂ else <{ [x := s] t₂ }>
<{ let y = [x := s] t₁ in t₂ }>)
-- fix
| .fix t₁ => solution!(<{ fix ([x := s] t₁) }>)
Notation encoding
open Lean PrettyPrinter in
@[app_unexpander subst]
def unexpandSubst : Unexpander := StlcCommon.Delab.unexpandSubst
Make sure the following tests are valid by reflexivity:
example : <{ [Z := 0] (let W = Z in Z) }> = <{ let W = 0 in 0 }> := ⊢ <{ [Z := 0] (let W = Z in Z) }> = <{ let W = 0 in 0 }>
solution!
All goals completed! 🐙
example : <{ [Z := 0] (let W = Z in W) }> = <{ let W = 0 in W }> := ⊢ <{ [Z := 0] (let W = Z in W) }> = <{ let W = 0 in W }>
solution!
All goals completed! 🐙
example : <{ [Z := 0] (let Y = succ 0 in Z) }> = <{ let Y = succ 0 in 0 }> := ⊢ <{ [Z := 0] (let Y = succ 0 in Z) }> = <{ let Y = succ 0 in 0 }>
solution!
All goals completed! 🐙
Next we define the values of our language.
inductive Tm.IsValue : Tm → Prop where
-- In pure STLC, function abstractions are values:
| abs (x : String) (τ₂ : Ty) (t₁ : Tm) : IsValue <{λ x : τ₂ . t₁}>
-- Numbers are values:
| nat (n : Nat) : IsValue (.const n)
-- A tagged value is a value:
| sumInl (v : Tm) (τ₁ : Ty) :
IsValue v →
IsValue <{inl τ₁ v}>
| sumInr (v : Tm) (τ₁ : Ty) :
IsValue v →
IsValue <{inr τ₁ v}>
-- A list is a value iff its head and tail are values:
| listNil (τ₁ : Ty) : IsValue <{nil τ₁}>
| listCons (v₁ v₂ : Tm) :
IsValue v₁ →
IsValue v₂ →
IsValue <{v₁ :: v₂}>
-- A unit is always a value
| unit : IsValue <{unit}>
-- A pair is a value if both components are:
| pair (v₁ v₂ : Tm) :
IsValue v₁ →
IsValue v₂ →
IsValue <{(v₁, v₂)}>
attribute [ExtStlcEval] Tm.IsValue.abs Tm.IsValue.nat Tm.IsValue.sumInl Tm.IsValue.sumInr
Tm.IsValue.listNil Tm.IsValue.listCons Tm.IsValue.unit Tm.IsValue.pair
section
set_option hygiene false in
local notation:40 t:41 " ⟶ " t':41 => Step t t'
inductive Step : Tm → Tm → Prop where
-- pure STLC
| appAbs (x : String) (τ₂ : Ty) (t₁ v₂ : Tm) :
v₂.IsValue →
<{(λ x: τ₂ . t₁) v₂}> ⟶ <{ [x := v₂] t₁ }>
| app₁ (t₁ t₁' t₂ : Tm) :
t₁ ⟶ t₁' →
<{t₁ t₂}> ⟶ <{t₁' t₂}>
| app₂ (v₁ t₂ t₂' : Tm) :
v₁.IsValue →
t₂ ⟶ t₂' →
<{v₁ t₂}> ⟶ <{v₁ t₂'}>
-- numbers
| succ (t₁ t₁' : Tm) :
t₁ ⟶ t₁' →
<{succ t₁}> ⟶ <{succ t₁'}>
| succNat (n : Nat) :
<{ succ ~(Tm.const n) }> ⟶ Tm.const (n + 1)
| pred (t₁ t₁' : Tm) (h : t₁ ⟶ t₁') :
<{ pred t₁ }> ⟶ <{ pred t₁' }>
| predConst (n : Nat) :
<{ pred ~(Tm.const n) }> ⟶ Tm.const (n - 1)
| multConst (n₁ n₂ : Nat) :
<{ ~(Tm.const n₁) * ~(Tm.const n₂) }> ⟶ Tm.const (n₁ * n₂)
| mult₁ (t₁ t₁' t₂ : Tm) (h : t₁ ⟶ t₁') :
<{ t₁ * t₂ }> ⟶ <{ t₁' * t₂ }>
| mult₂ (v₁ t₂ t₂' : Tm) (hv : v₁.IsValue) (h : t₂ ⟶ t₂') :
<{ v₁ * t₂ }> ⟶ <{ v₁ * t₂' }>
| if0Step (t₁ t₁' t₂ t₃ : Tm) (h : t₁ ⟶ t₁') :
<{ if0 t₁ then t₂ else t₃ }> ⟶ <{ if0 t₁' then t₂ else t₃ }>
| if0Zero (t₂ t₃ : Tm) :
<{ if0 0 then t₂ else t₃ }> ⟶ t₂
| if0Nonzero (n : Nat) (t₂ t₃ : Tm) :
<{ if0 ~(Tm.const (n + 1)) then t₂ else t₃ }> ⟶ t₃
-- sums
| sumInl (t₁ t₁' : Tm) (τ₂ : Ty) :
t₁ ⟶ t₁' →
<{inl τ₂ t₁}> ⟶ <{inl τ₂ t₁'}>
| sumInr (t₂ t₂' : Tm) (τ₁ : Ty) :
t₂ ⟶ t₂' →
<{inr τ₁ t₂}> ⟶ <{inr τ₁ t₂'}>
| sumCase (t t' : Tm) (x₁ : String) (t₁ : Tm) (x₂ : String) (t₂ : Tm) :
t ⟶ t' →
<{case t of inl x₁ => t₁ | inr x₂ => t₂}> ⟶
<{case t' of inl x₁ => t₁ | inr x₂ => t₂}>
| sumCaseInl (v : Tm) (x₁:String) (t₁ : Tm) (x₂ : String) (t₂ : Tm) (τ₂ : Ty) :
v.IsValue →
<{case inl τ₂ v of inl x₁ => t₁ | inr x₂ => t₂}> ⟶ <{ [x₁ := v] t₁ }>
| sumCaseInr (v : Tm) (x₁:String) (t₁ : Tm) (x₂ : String) (t₂ : Tm) (τ₁ : Ty) :
v.IsValue →
<{case inr τ₁ v of inl x₁ => t₁ | inr x₂ => t₂}> ⟶ <{ [x₂ := v] t₂ }>
-- lists
| cons₁ (t₁ t₁' t₂ : Tm) :
t₁ ⟶ t₁' →
<{t₁ :: t₂}> ⟶ <{t₁' :: t₂}>
| cons₂ (v₁ t₂ t₂' : Tm) :
v₁.IsValue →
t₂ ⟶ t₂' →
<{v₁ :: t₂}> ⟶ <{v₁ :: t₂'}>
| listCase₁ (t₁ t₁' t₂ : Tm) (x₁ x₂ : String) (t₃ : Tm) :
t₁ ⟶ t₁' →
<{case t₁ of nil => t₂ | x₁ :: x₂ => t₃}> ⟶
<{case t₁' of nil => t₂ | x₁ :: x₂ => t₃}>
| listCaseNil (τ₁ : Ty) (t₂ : Tm) (x₁ x₂ : String) (t₃ : Tm) :
<{case nil τ₁ of nil => t₂ | x₁ :: x₂ => t₃}> ⟶ t₂
| listCaseCons (v₁ vl t₂ : Tm) (x₁ x₂ : String) (t₃ : Tm) :
v₁.IsValue →
vl.IsValue →
<{case v₁ :: vl of nil => t₂ | x₁ :: x₂ => t₃}>
⟶ <{ [x₂ := vl] ([x₁ := v₁] t₃) }>
-- Add rules for the following extensions.
-- pairs
| pair₁ (t₁ t₁' t₂ : Tm) :
t₁ ⟶ t₁' →
<{ (t₁, t₂) }> ⟶ <{ (t₁' , t₂) }>
| pair₂ (v₁ t₂ t₂' : Tm) :
v₁.IsValue →
t₂ ⟶ t₂' →
<{ (v₁, t₂) }> ⟶ <{ (v₁, t₂') }>
| fst₁ (t t' : Tm) :
t ⟶ t' →
<{ fst t }> ⟶ <{ fst t' }>
| fstPair (v₁ v₂ : Tm) :
v₁.IsValue →
v₂.IsValue →
<{ fst (v₁ , v₂) }> ⟶ v₁
| snd₁ (t t' : Tm) :
t ⟶ t' →
<{ snd t }> ⟶ <{ snd t' }>
| sndPair (v₁ v₂ : Tm) :
v₁.IsValue →
v₂.IsValue →
<{ snd (v₁, v₂) }> ⟶ v₂
-- let
| let₁ (x : String) (t₁ t₁' t₂ : Tm) :
t₁ ⟶ t₁' →
<{ let x = t₁ in t₂}> ⟶ <{ let x = t₁' in t₂ }>
| letValue (x : String) (v₁ t₂ : Tm) :
v₁.IsValue →
<{ let x = v₁ in t₂ }> ⟶ <{ [x := v₁] t₂ }>
-- fix
| fix₁ (t₁ t₁' : Tm) :
t₁ ⟶ t₁' →
<{ fix t₁ }> ⟶ <{ fix t₁' }>
| fixAbs (x : String) (τ₁ : Ty) (t₁ : Tm) :
<{ fix (λ x : τ₁ . t₁) }> ⟶
<{ [x := fix (λ x : τ₁ . t₁) ] t₁ }>
end
scoped notation:40 t:41 " ⟶ " t':41 => Step t t'
scoped notation:40 t:41 " ⟶* " t':41 => Multi Step t t'
-- Be sure to add your constructors to this list!
attribute [ExtStlcEval] Step.appAbs Step.app₁ Step.app₂
Step.succ Step.succNat Step.pred Step.predConst
Step.multConst Step.mult₁ Step.mult₂
Step.if0Step Step.if0Zero Step.if0Nonzero
Step.sumInl Step.sumInr Step.sumCase Step.sumCaseInl Step.sumCaseInr
Step.cons₁ Step.cons₂ Step.listCase₁ Step.listCaseNil
Step.listCaseCons
Step.pair₁ Step.pair₂ Step.fst₁ Step.fstPair
Step.snd₁ Step.sndPair Step.let₁ Step.letValue
Step.fix₁ Step.fixAbs
abbrev Context := PartialMap String Ty
inductive HasType : Context → Tm → Ty → Prop where
-- pure STLC
| var (Γ : Context) (x : String) (τ₁ : Ty) (h : Γ[x] = some τ₁) :
<{ Γ ⊢ ~(Tm.var x) ⦂ τ₁ }>
| abs (Γ : Context) (x : String) (τ₁ τ₂ : Ty) (t₁ : Tm)
(h : <{ x ↦ τ₂ ; Γ ⊢ t₁ ⦂ τ₁ }>) :
<{ Γ ⊢ λ x : τ₂ . t₁ ⦂ τ₂ → τ₁ }>
| app (Γ : Context) (τ₁ τ₂ : Ty) (t₁ t₂ : Tm)
(h₁ : <{ Γ ⊢ t₁ ⦂ τ₂ → τ₁ }>) (h₂ : <{ Γ ⊢ t₂ ⦂ τ₂ }>) :
<{ Γ ⊢ t₁ t₂ ⦂ τ₁ }>
-- numbers
| const (Γ : Context) (n : Nat) :
<{ Γ ⊢ ~(Tm.const n) ⦂ Nat }>
| succ (Γ : Context) (t₁ : Tm) (h : <{ Γ ⊢ t₁ ⦂ Nat }>) :
<{ Γ ⊢ succ t₁ ⦂ Nat }>
| pred (Γ : Context) (t₁ : Tm) (h : <{ Γ ⊢ t₁ ⦂ Nat }>) :
<{ Γ ⊢ pred t₁ ⦂ Nat }>
| mult (Γ : Context) (t₁ t₂ : Tm)
(h₁ : <{ Γ ⊢ t₁ ⦂ Nat }>) (h₂ : <{ Γ ⊢ t₂ ⦂ Nat }>) :
<{ Γ ⊢ t₁ * t₂ ⦂ Nat }>
| ite0 (Γ : Context) (t₁ t₂ t₃ : Tm) (τ : Ty)
(h₁ : <{ Γ ⊢ t₁ ⦂ Nat }>) (h₂ : <{ Γ ⊢ t₂ ⦂ τ }>)
(h₃ : <{ Γ ⊢ t₃ ⦂ τ }>) :
<{ Γ ⊢ if0 t₁ then t₂ else t₃ ⦂ τ }>
-- sums
| sumInl (Γ : Context) (t₁ : Tm) (τ₁ τ₂ : Ty) :
<{ Γ ⊢ t₁ ⦂ τ₁ }> →
<{ Γ ⊢ (inl τ₂ t₁) ⦂ τ₁ + τ₂ }>
| sumInr (Γ : Context) (t₂ : Tm) (τ₁ τ₂ : Ty) :
<{ Γ ⊢ t₂ ⦂ τ₂ }> →
<{ Γ ⊢ (inr τ₁ t₂) ⦂ τ₁ + τ₂ }>
| sumCase (Γ : Context) (x₁ x₂ : String) (τ₁ τ₂ τ₃: Ty) (t t₁ t₂ : Tm) :
<{ Γ ⊢ t ⦂ τ₁ + τ₂ }> →
<{ x₁ ↦ τ₁ ; Γ ⊢ t₁ ⦂ τ₃ }> →
<{ x₂ ↦ τ₂ ; Γ ⊢ t₂ ⦂ τ₃ }> →
<{ Γ ⊢ case t of inl x₁ => t₁ | inr x₂ => t₂ ⦂ τ₃ }>
-- lists
| listNil (Γ : Context) (τ₁ : Ty) :
<{ Γ ⊢ nil τ₁ ⦂ [τ₁] }>
| listCons (Γ : Context) (t₁ t₂ : Tm) (τ₁ : Ty) :
<{ Γ ⊢ t₁ ⦂ τ₁ }> →
<{ Γ ⊢ t₂ ⦂ [τ₁] }> →
<{ Γ ⊢ t₁ :: t₂ ⦂ [τ₁] }>
| listCase (Γ : Context) (t₁ t₂ t₃ : Tm) (x₁ x₂ : String) (τ₁ τ₂ : Ty) :
<{ Γ ⊢ t₁ ⦂ [τ₁] }> →
<{ Γ ⊢ t₂ ⦂ τ₂ }> →
<{ x₁ ↦ τ₁ ; x₂ ↦ [τ₁] ; Γ ⊢ t₃ ⦂ τ₂ }> →
<{ Γ ⊢ case t₁ of nil => t₂ | x₁ :: x₂ => t₃ ⦂ τ₂ }>
-- unit
| unit (Γ : Context) :
<{ Γ ⊢ unit ⦂ Unit }>
-- Add rules for the following extensions.
-- pairs
| pair (Γ : Context) (t₁ t₂ : Tm) (τ₁ τ₂ : Ty) :
<{ Γ ⊢ t₁ ⦂ τ₁ }> →
<{ Γ ⊢ t₂ ⦂ τ₂ }> →
<{ Γ ⊢ (t₁, t₂) ⦂ τ₁ × τ₂ }>
| fst (Γ : Context) (t : Tm) (τ₁ τ₂ : Ty) :
<{ Γ ⊢ t ⦂ τ₁ × τ₂ }> →
<{ Γ ⊢ fst t ⦂ τ₁ }>
| snd (Γ : Context) (t : Tm) (τ₁ τ₂ : Ty) :
<{ Γ ⊢ t ⦂ τ₁ × τ₂ }> →
<{ Γ ⊢ snd t ⦂ τ₂ }>
-- let
| letIn (Γ : Context) (x : String) (t₁ t₂ : Tm) (τ₁ τ₂ : Ty) :
<{ Γ ⊢ t₁ ⦂ τ₁ }> →
<{ x ↦ τ₁ ; Γ ⊢ t₂ ⦂ τ₂ }> →
<{ Γ ⊢ let x = t₁ in t₂ ⦂ τ₂ }>
-- fix
| fix (Γ : Context) (t₁ : Tm) (τ₁ : Ty) :
<{ Γ ⊢ t₁ ⦂ τ₁ → τ₁ }> →
<{ Γ ⊢ fix t₁ ⦂ τ₁ }>
-- Make sure to add your constructors here
attribute [ExtStlcTyping] HasType.var HasType.abs HasType.app
HasType.const HasType.succ HasType.pred HasType.mult
HasType.ite0 HasType.sumInl HasType.sumInr HasType.sumCase
HasType.listNil HasType.listCons HasType.listCase HasType.unit
HasType.pair HasType.fst HasType.snd HasType.letIn HasType.fix
Notation encoding
open Lean PrettyPrinter in
@[app_unexpander HasType]
def HasType.unexpand : Unexpander := StlcCommon.Delab.unexpandHasType
This section presents formalized versions of the examples from above (plus several more).
For each example, replace sorry once you've implemented enough of
the definitions for the tests to pass. If you've defined
Step and HasType correctly, these should
all be solvable with apply_rules using ExtStlcTyping or
normalize using ExtStlcEval. Make sure to give your new
constructors the right attributes so that Lean can find them.
If these don't work, try working the proofs by applying constructors
manually to see where they go wrong.
The examples at the beginning focus on specific features; you can use these to make sure your definition of a given feature is reasonable before moving on to extending the proofs later in the file with the cases relating to this feature. The later examples require all the features together, so you'll need to come back to these when you've got all the definitions filled in.
namespace Examples
namespace Numbers
def tm_test := <{if0 (pred (succ (pred (2 * 0)))) then 5 else 6}>
theorem typechecks : <{ ∅ ⊢ tm_test ⦂ Nat }> := ⊢ <{ ∅ ⊢ tm_test ⦂ Nat }>
solution!
All goals completed! 🐙
theorem reduces : tm_test ⟶* (Tm.const 5) := ⊢ tm_test ⟶* <{ 5 }>
solution!
All goals completed! 🐙
end Numbers
namespace Prod
def tm_test := <{ snd (fst ((5, 6), 7)) }>
theorem typechecks : <{ ∅ ⊢ tm_test ⦂ Nat }> := ⊢ <{ ∅ ⊢ tm_test ⦂ Nat }>
solution!
All goals completed! 🐙
theorem reduces : tm_test ⟶* Tm.const 6 := ⊢ tm_test ⟶* <{ 6 }>
solution!
All goals completed! 🐙
end Prod
namespace Let
def tm_test := <{ let X = (pred 6) in (succ X) }>
theorem typechecks : <{ ∅ ⊢ tm_test ⦂ Nat }> := ⊢ <{ ∅ ⊢ tm_test ⦂ Nat }>
solution!
All goals completed! 🐙
theorem reduces :
tm_test ⟶* Tm.const 6 := ⊢ tm_test ⟶* <{ 6 }>
solution!
All goals completed! 🐙
end Let
namespace Let1
def tm_test :=
<{ let Z = pred 6 in
(succ Z) }>
theorem typechecks :
<{ ∅ ⊢ tm_test ⦂ Nat }> := ⊢ <{ ∅ ⊢ tm_test ⦂ Nat }>
solution!
All goals completed! 🐙
theorem reduces :
tm_test ⟶* Tm.const 6 := ⊢ tm_test ⟶* <{ 6 }>
solution!
All goals completed! 🐙
end Let1
namespace Sums1
def tm_test :=
<{ case (inl Nat 5) of
inl X => X
| inr Y => Y }>
theorem typechecks :
<{ ∅ ⊢ tm_test ⦂ Nat }> := ⊢ <{ ∅ ⊢ tm_test ⦂ Nat }>
solution!
All goals completed! 🐙
theorem reduces :
tm_test ⟶* Tm.const 5 := ⊢ tm_test ⟶* <{ 5 }>
solution!
All goals completed! 🐙
end Sums1
namespace Sums2
def tm_test :=
<{ let ProcessSum =
(λ X : Nat + Nat .
case X of
inl N => N
| inr N => (if0 N then 1 else 0)) in
(ProcessSum (inl Nat 5), ProcessSum (inr Nat 5)) }>
theorem typechecks :
<{ ∅ ⊢ tm_test ⦂ Nat × Nat }> := ⊢ <{ ∅ ⊢ tm_test ⦂ Nat × Nat }>
solution!
All goals completed! 🐙
theorem reduces :
tm_test ⟶* <{ (5, ~(Tm.const 0)) }> := ⊢ tm_test ⟶* <{ ( 5 , 0 ) }>
solution!
All goals completed! 🐙
end Sums2
namespace Lists
def tm_test :=
<{ let L = (5 :: 6 :: (nil Nat)) in
case L of
nil => 0
| X :: Xs => (X * X) }>
theorem typechecks :
<{ ∅ ⊢ tm_test ⦂ Nat }> := ⊢ <{ ∅ ⊢ tm_test ⦂ Nat }>
solution!
All goals completed! 🐙
theorem reduces :
tm_test ⟶* Tm.const 25 := ⊢ tm_test ⟶* <{ 25 }>
solution!
All goals completed! 🐙
end Lists
namespace Fix1
def fact :=
<{ fix
(λ F : Nat → Nat .
λ A : Nat .
if0 A then 1 else (A * (F (pred A)))) }>
-- (Warning: you may be able to typecheck `fact` but still have some rules wrong!) *)
theorem typechecks :
<{ ∅ ⊢ fact ⦂ Nat → Nat }> := ⊢ <{ ∅ ⊢ fact ⦂ Nat → Nat }>
solution!
All goals completed! 🐙
theorem reduces :
<{ fact 4 }> ⟶* Tm.const 24 := ⊢ <{ fact 4 }> ⟶* <{ 24 }>
solution!
All goals completed! 🐙
end Fix1
namespace Fix2
def map :=
<{ λ G : Nat → Nat .
fix
(λ F : [Nat] → [Nat] .
λ L : [Nat] .
case L of
nil => nil Nat
| X :: Xs => ((G X) :: (F Xs))) }>
theorem typechecks :
<{ ∅ ⊢ map ⦂
(Nat → Nat) → [Nat] → [Nat] }> := ⊢ <{ ∅ ⊢ map ⦂ (Nat → Nat) → [ Nat ] → [ Nat ] }>
solution!
All goals completed! 🐙
theorem reduces :
<{ map (λ A : Nat . succ A) (1 :: 2 :: (nil Nat)) }>
⟶* <{ 2 :: 3 :: (nil Nat) }> := ⊢ <{ map (λ A : Nat . succ A) (1 :: 2 :: nil Nat) }> ⟶* <{ 2 :: 3 :: nil Nat }>
solution!
All goals completed! 🐙
end Fix2
namespace Fix3
def equal :=
<{ fix
(λ Eq : Nat → Nat → Nat .
λ M : Nat . λ N : Nat .
if0 M then (if0 N then 1 else 0)
else (if0 N
then 0
else (Eq (pred M) (pred N)))) }>
theorem typechecks :
<{ ∅ ⊢ equal ⦂ Nat → Nat → Nat }> := ⊢ <{ ∅ ⊢ equal ⦂ Nat → Nat → Nat }>
solution!
All goals completed! 🐙
theorem reduces :
<{ equal 4 4 }> ⟶* Tm.const 1 := ⊢ <{ equal 4 4 }> ⟶* <{ 1 }>
solution!
All goals completed! 🐙
theorem reduces2 :
<{ equal 4 5 }> ⟶* Tm.const 0 := ⊢ <{ equal 4 5 }> ⟶* <{ 0 }>
solution!
All goals completed! 🐙
end Fix3
namespace Fix4
def eotest :=
<{ let EvenOdd =
fix
(λ Eo : (Nat → Nat) × (Nat → Nat) .
((λ N : Nat . if0 N then 1 else (snd Eo (pred N))),
(λ N : Nat . if0 N then 0 else (fst Eo (pred N))))) in
let Even = fst EvenOdd in
let Odd = snd EvenOdd in
(Even 3, Even 4) }>
theorem typechecks :
<{ ∅ ⊢ eotest ⦂ Nat × Nat }> := ⊢ <{ ∅ ⊢ eotest ⦂ Nat × Nat }>
solution!
All goals completed! 🐙
theorem reduces :
eotest ⟶* <{ (0, 1) }> := ⊢ eotest ⟶* <{ ( 0 , 1 ) }>
solution!
All goals completed! 🐙
end Fix4
end Examples
The proofs of progress and preservation for this enriched system are essentially the same (though of course longer) as for the pure STLC.
Complete the proof of progress
Theorem: Suppose ∅ ⊢ t ⦂ τ. Then either
-
tis a value, or -
t ⟶ t'for somet'.
Proof: By induction on the given typing derivation.
theorem canonical_forms_fun (t : Tm) (τ₁ τ₂ : Ty)
(ht : <{ ∅ ⊢ t ⦂ τ₁ → τ₂ }>) (hv : t.IsValue) :
∃ x u, t = <{ λ x : τ₁ . u }> := t:Tmτ₁:Tyτ₂:Tyht:<{ ∅ ⊢ t ⦂ τ₁ → τ₂ }>hv:t.IsValue⊢ ∃ x u, t = <{ λ ~x : τ₁ . u }>
inversion ht with (All goals completed! 🐙)
| abs x t h => All goals completed! 🐙
theorem canonical_forms_nat (t : Tm)
(ht : <{ ∅ ⊢ t ⦂ Nat }>) (hv : t.IsValue) :
∃ n, t = Tm.const n := t:Tmht:<{ ∅ ⊢ t ⦂ Nat }>hv:t.IsValue⊢ ∃ n, t = Tm.const n
inversion ht with (All goals completed! 🐙)
| nat n => All goals completed! 🐙
theorem canonical_forms_sum {t : Tm} {τ₁ τ₂ : Ty}
(ht : <{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>) (hv : t.IsValue) :
∃ v, v.IsValue ∧ (t = <{inl τ₂ v}> ∨ t = <{inr τ₁ v}>) := t:Tmτ₁:Tyτ₂:Tyht:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>hv:t.IsValue⊢ ∃ v, v.IsValue ∧ (t = <{ inl τ₂ v }> ∨ t = <{ inr τ₁ v }>)
inversion ht with (All goals completed! 🐙)
| sumInl v ht hv =>
τ₁:Tyτ₂:Tyv:Tmht:<{ ∅ ⊢ v ⦂ τ₁ }>hv:v.IsValue⊢ v.IsValue ∧ (<{ inl τ₂ v }> = <{ inl τ₂ v }> ∨ <{ inl τ₂ v }> = <{ inr τ₁ v }>); τ₁:Tyτ₂:Tyv:Tmht:<{ ∅ ⊢ v ⦂ τ₁ }>hv:v.IsValue⊢ v.IsValueτ₁:Tyτ₂:Tyv:Tmht:<{ ∅ ⊢ v ⦂ τ₁ }>hv:v.IsValue⊢ <{ inl τ₂ v }> = <{ inl τ₂ v }> ∨ <{ inl τ₂ v }> = <{ inr τ₁ v }>; τ₁:Tyτ₂:Tyv:Tmht:<{ ∅ ⊢ v ⦂ τ₁ }>hv:v.IsValue⊢ <{ inl τ₂ v }> = <{ inl τ₂ v }> ∨ <{ inl τ₂ v }> = <{ inr τ₁ v }>; τ₁:Tyτ₂:Tyv:Tmht:<{ ∅ ⊢ v ⦂ τ₁ }>hv:v.IsValue⊢ <{ inl τ₂ v }> = <{ inl τ₂ v }>; All goals completed! 🐙
| sumInr v ht hv =>
τ₁:Tyτ₂:Tyv:Tmht:<{ ∅ ⊢ v ⦂ τ₂ }>hv:v.IsValue⊢ v.IsValue ∧ (<{ inr τ₁ v }> = <{ inl τ₂ v }> ∨ <{ inr τ₁ v }> = <{ inr τ₁ v }>); τ₁:Tyτ₂:Tyv:Tmht:<{ ∅ ⊢ v ⦂ τ₂ }>hv:v.IsValue⊢ v.IsValueτ₁:Tyτ₂:Tyv:Tmht:<{ ∅ ⊢ v ⦂ τ₂ }>hv:v.IsValue⊢ <{ inr τ₁ v }> = <{ inl τ₂ v }> ∨ <{ inr τ₁ v }> = <{ inr τ₁ v }>; τ₁:Tyτ₂:Tyv:Tmht:<{ ∅ ⊢ v ⦂ τ₂ }>hv:v.IsValue⊢ <{ inr τ₁ v }> = <{ inl τ₂ v }> ∨ <{ inr τ₁ v }> = <{ inr τ₁ v }>; τ₁:Tyτ₂:Tyv:Tmht:<{ ∅ ⊢ v ⦂ τ₂ }>hv:v.IsValue⊢ <{ inr τ₁ v }> = <{ inr τ₁ v }>; All goals completed! 🐙
theorem canonical_forms_list {t : Tm} {τ : Ty}
(ht : <{ ∅ ⊢ t ⦂ [τ] }>) (hv : t.IsValue) :
t = <{ nil τ }> ∨ ∃ v₁ v₂, (v₁.IsValue ∧ v₂.IsValue ∧ t = <{v₁ :: v₂}>) := t:Tmτ:Tyht:<{ ∅ ⊢ t ⦂ [ τ ] }>hv:t.IsValue⊢ t = <{ nil τ }> ∨ ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t = <{ v₁ :: v₂ }>
inversion ht with (All goals completed! 🐙)
| listNil _ => τ:Ty⊢ <{ nil τ }> = <{ nil τ }>; All goals completed! 🐙
| listCons v₁ v₂ _ _ _ _ => τ:Tyv₁:Tmv₂:Tma✝³:<{ ∅ ⊢ v₁ ⦂ τ }>a✝²:<{ ∅ ⊢ v₂ ⦂ [ τ ] }>a✝¹:v₁.IsValuea✝:v₂.IsValue⊢ ∃ v₁_1 v₂_1, v₁_1.IsValue ∧ v₂_1.IsValue ∧ <{ v₁ :: v₂ }> = <{ v₁_1 :: v₂_1 }>; All goals completed! 🐙
-- Add your own canonical forms lemmas here as needed
theorem canonical_forms_prod {t : Tm} {τ₁ τ₂ : Ty}
(ht : <{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>) (hv : t.IsValue) :
∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t = <{(v₁, v₂)}> := t:Tmτ₁:Tyτ₂:Tyht:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>hv:t.IsValue⊢ ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t = <{ ( v₁ , v₂ ) }>
inversion ht with (All goals completed! 🐙)
| pair v₁ v₂ _ _ _ _ => All goals completed! 🐙
theorem progress (t : Tm) (τ : Ty) (ht :<{ ∅ ⊢ t ⦂ τ }>) :
t.IsValue ∨ exists t', t ⟶ t' := t:Tmτ:Tyht:<{ ∅ ⊢ t ⦂ τ }>⊢ t.IsValue ∨ ∃ t', t ⟶ t'
t:Tmτ:TyΓ:Contextheq:∅ = Γht:<{ Γ ⊢ t ⦂ τ }>⊢ t.IsValue ∨ ∃ t', t ⟶ t'
induction ht with (t:Tmτ:TyΓ:Context⊢ <{ unit }>.IsValue ∨ ∃ t', <{ unit }> ⟶ t'; first
-- discharge cases where `t` is obviously a value
| try (t:Tmτ:TyΓ:Context⊢ <{ unit }>.IsValue; All goals completed! 🐙; All goals completed! 🐙)
)
t:Tmτ:TyΓ:Contextx✝:Stringτ₁✝:Tyh✝:∅[x✝] = some τ₁✝⊢ (StlcExtended.Tm.var x✝).IsValue ∨ ∃ t', StlcExtended.Tm.var x✝ ⟶ t' All goals completed! 🐙
t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'⊢ <{ t₁ t₂ }>.IsValue ∨ ∃ t', <{ t₁ t₂ }> ⟶ t'
t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'; t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'h✝:t₁.IsValue⊢ ∃ t', <{ t₁ t₂ }> ⟶ t't:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'h✝:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
-- t₁ is a value
case _ ht₁ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValue⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueh✝:t₂.IsValue⊢ ∃ t', <{ t₁ t₂ }> ⟶ t't:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueh✝:∃ t', t₂ ⟶ t'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
-- t₂ is a value
case _ ht₂ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:t₂.IsValue⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:t₂.IsValueh₁:t₁.IsValue → ∃ x u, t₁ = <{ λ ~x : τ₂ . u }>⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:t₂.IsValueh₁:t₁.IsValue → ∃ x u, t₁ = <{ λ ~x : τ₂ . u }>x:Stringv:Tmhv:t₁ = <{ λ ~x : τ₂ . v }>⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:t₂.IsValueh₁:t₁.IsValue → ∃ x u, t₁ = <{ λ ~x : τ₂ . u }>x:Stringv:Tmhv:t₁ = <{ λ ~x : τ₂ . v }>⊢ <{ t₁ t₂ }> ⟶ <{ [~x := t₂] v }>; t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:t₂.IsValueh₁:t₁.IsValue → ∃ x u, t₁ = <{ λ ~x : τ₂ . u }>x:Stringv:Tmhv:t₁ = <{ λ ~x : τ₂ . v }>⊢ <{ (λ ~x : τ₂ . v) t₂ }> ⟶ <{ [~x := t₂] v }>
All goals completed! 🐙
-- t₂ is not a value
case _ ht₂ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:∃ t', t₂ ⟶ t'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValuet₂':Tmht₂:t₂ ⟶ t₂'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValuet₂':Tmht₂:t₂ ⟶ t₂'⊢ <{ t₁ t₂ }> ⟶ <{ t₁ t₂' }>; All goals completed! 🐙
-- t₁ is not a value
case _ ht₁ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ <{ t₁ t₂ }> ⟶ <{ t₁' t₂ }>; All goals completed! 🐙
t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ t₁ ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'⊢ <{ succ t₁ }>.IsValue ∨ ∃ t', <{ succ t₁ }> ⟶ t'
t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ t₁ ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'⊢ ∃ t', <{ succ t₁ }> ⟶ t'; t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ t₁ ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'h✝:t₁.IsValue⊢ ∃ t', <{ succ t₁ }> ⟶ t't:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ t₁ ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'h✝:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ succ t₁ }> ⟶ t'
-- t₁ is a value
case _ ht₁ t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ t₁ ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValue⊢ ∃ t', <{ succ t₁ }> ⟶ t'
t:Tmτ:TyΓ:Contextt₁:Tmih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValueh:t₁.IsValue → ∃ n, t₁ = Tm.const n⊢ ∃ t', <{ succ t₁ }> ⟶ t'
t:Tmτ:TyΓ:Contextt₁:Tmih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValueh✝:t₁.IsValue → ∃ n, t₁ = Tm.const nn:Nath:t₁ = Tm.const n⊢ ∃ t', <{ succ t₁ }> ⟶ t'; t:Tmτ:TyΓ:Contextt₁:Tmih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValueh✝:t₁.IsValue → ∃ n, t₁ = Tm.const nn:Nath:t₁ = Tm.const n⊢ ∃ t', <{ succ ~(Tm.const n) }> ⟶ t'
exists (Tm.const (n + 1)) t:Tmτ:TyΓ:Contextt₁:Tmih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValueh✝:t₁.IsValue → ∃ n, t₁ = Tm.const nn:Nath:t₁ = Tm.const n⊢ <{ succ ~(Tm.const n) }> ⟶ Tm.const (n + 1); apply_rules using ExtStlcEval All goals completed! 🐙
-- t₁ is not a value
case _ ht₁ => t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ t₁ ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ succ t₁ }> ⟶ t'
obtain ⟨t₁', ht₁⟩ := ht₁ t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ t₁ ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ ∃ t', <{ succ t₁ }> ⟶ t'
exists <{succ t₁'}> t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ t₁ ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ <{ succ t₁ }> ⟶ <{ succ t₁' }>; apply_rules using ExtStlcEval All goals completed! 🐙
| pred Γ t₁ h ih => pred t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ t₁ ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'⊢ <{ pred t₁ }>.IsValue ∨ ∃ t', <{ pred t₁ }> ⟶ t'
right pred t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ t₁ ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'⊢ ∃ t', <{ pred t₁ }> ⟶ t'; cases ih rfl pred.inl t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ t₁ ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'h✝:t₁.IsValue⊢ ∃ t', <{ pred t₁ }> ⟶ t'pred.inr t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ t₁ ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'h✝:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ pred t₁ }> ⟶ t'
-- t₁ is a value
case _ ht₁ => t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ t₁ ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValue⊢ ∃ t', <{ pred t₁ }> ⟶ t'
apply canonical_forms_nat at h t:Tmτ:TyΓ:Contextt₁:Tmih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValueh:t₁.IsValue → ∃ n, t₁ = Tm.const n⊢ ∃ t', <{ pred t₁ }> ⟶ t'
obtain ⟨n, h⟩ := h ht₁ t:Tmτ:TyΓ:Contextt₁:Tmih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValueh✝:t₁.IsValue → ∃ n, t₁ = Tm.const nn:Nath:t₁ = Tm.const n⊢ ∃ t', <{ pred t₁ }> ⟶ t'; rw [h t:Tmτ:TyΓ:Contextt₁:Tmih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValueh✝:t₁.IsValue → ∃ n, t₁ = Tm.const nn:Nath:t₁ = Tm.const n⊢ ∃ t', <{ pred ~(Tm.const n) }> ⟶ t'] t:Tmτ:TyΓ:Contextt₁:Tmih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValueh✝:t₁.IsValue → ∃ n, t₁ = Tm.const nn:Nath:t₁ = Tm.const n⊢ ∃ t', <{ pred ~(Tm.const n) }> ⟶ t'
exists (Tm.const (n - 1)) t:Tmτ:TyΓ:Contextt₁:Tmih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValueh✝:t₁.IsValue → ∃ n, t₁ = Tm.const nn:Nath:t₁ = Tm.const n⊢ <{ pred ~(Tm.const n) }> ⟶ Tm.const (n - 1); apply_rules using ExtStlcEval All goals completed! 🐙
case _ ht₁ => t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ t₁ ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ pred t₁ }> ⟶ t'
obtain ⟨t₁', ht₁⟩ := ht₁ t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ t₁ ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ ∃ t', <{ pred t₁ }> ⟶ t'
exists <{pred t₁'}> t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ t₁ ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ <{ pred t₁ }> ⟶ <{ pred t₁' }>; apply_rules using ExtStlcEval All goals completed! 🐙
| mult Γ t₁ t₂ h₁ h₂ ih₁ ih₂ => mult t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'⊢ <{ t₁ * t₂ }>.IsValue ∨ ∃ t', <{ t₁ * t₂ }> ⟶ t'
right mult t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'; cases ih₁ rfl mult.inl t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'h✝:t₁.IsValue⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'mult.inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'h✝:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
-- t₁ is a value
case _ ht₁ => t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValue⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
cases ih₂ rfl inl t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueh✝:t₂.IsValue⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueh✝:∃ t', t₂ ⟶ t'⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
-- t₂ is a value
case _ ht₂ => t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:t₂.IsValue⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
apply canonical_forms_nat at h₁ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₂:<{ ∅ ⊢ t₂ ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:t₂.IsValueh₁:t₁.IsValue → ∃ n, t₁ = Tm.const n⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
apply canonical_forms_nat at h₂ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:t₂.IsValueh₁:t₁.IsValue → ∃ n, t₁ = Tm.const nh₂:t₂.IsValue → ∃ n, t₂ = Tm.const n⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
let ⟨n₁, h₁⟩ := h₁ ht₁ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:t₂.IsValueh₁✝:t₁.IsValue → ∃ n, t₁ = Tm.const nh₂:t₂.IsValue → ∃ n, t₂ = Tm.const nn₁:Nath₁:t₁ = Tm.const n₁⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
let ⟨n₂, h₂⟩ := h₂ ht₂ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:t₂.IsValueh₁✝:t₁.IsValue → ∃ n, t₁ = Tm.const nh₂✝:t₂.IsValue → ∃ n, t₂ = Tm.const nn₁:Nath₁:t₁ = Tm.const n₁n₂:Nath₂:t₂ = Tm.const n₂⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
exists (Tm.const (n₁ * n₂)) t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:t₂.IsValueh₁✝:t₁.IsValue → ∃ n, t₁ = Tm.const nh₂✝:t₂.IsValue → ∃ n, t₂ = Tm.const nn₁:Nath₁:t₁ = Tm.const n₁n₂:Nath₂:t₂ = Tm.const n₂⊢ <{ t₁ * t₂ }> ⟶ Tm.const (n₁ * n₂); simp [h₁, h₂] t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:t₂.IsValueh₁✝:t₁.IsValue → ∃ n, t₁ = Tm.const nh₂✝:t₂.IsValue → ∃ n, t₂ = Tm.const nn₁:Nath₁:t₁ = Tm.const n₁n₂:Nath₂:t₂ = Tm.const n₂⊢ <{ ~(Tm.const n₁) * ~(Tm.const n₂) }> ⟶ Tm.const (n₁ * n₂)
apply_rules using ExtStlcEval All goals completed! 🐙
-- t₂ is not a value
case _ ht₂ => t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:∃ t', t₂ ⟶ t'⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
obtain ⟨t₂', ht₂⟩ := ht₂ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValuet₂':Tmht₂:t₂ ⟶ t₂'⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
exists <{t₁ * t₂'}> t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValuet₂':Tmht₂:t₂ ⟶ t₂'⊢ <{ t₁ * t₂ }> ⟶ <{ t₁ * t₂' }>; apply_rules using ExtStlcEval All goals completed! 🐙
-- t₁ is not a value
case _ ht₁ => t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
obtain ⟨t₁', ht₁⟩ := ht₁ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
exists <{t₁' * t₂}> t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ <{ t₁ * t₂ }> ⟶ <{ t₁' * t₂ }>; apply_rules using ExtStlcEval All goals completed! 🐙
| ite0 Γ t₁ t₂ t₃ τ h₁ h₂ h₃ ih₁ ih₂ ih₃ => ite0 t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'⊢ <{ if0 t₁ then t₂ else t₃ }>.IsValue ∨ ∃ t', <{ if0 t₁ then t₂ else t₃ }> ⟶ t'
right ite0 t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'⊢ ∃ t', <{ if0 t₁ then t₂ else t₃ }> ⟶ t'; cases ih₁ rfl ite0.inl t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'h✝:t₁.IsValue⊢ ∃ t', <{ if0 t₁ then t₂ else t₃ }> ⟶ t'ite0.inr t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'h✝:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ if0 t₁ then t₂ else t₃ }> ⟶ t'
-- t₁ is a value
case _ ht₁ => t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht₁:t₁.IsValue⊢ ∃ t', <{ if0 t₁ then t₂ else t₃ }> ⟶ t'
apply canonical_forms_nat at h₁ t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht₁:t₁.IsValueh₁:t₁.IsValue → ∃ n, t₁ = Tm.const n⊢ ∃ t', <{ if0 t₁ then t₂ else t₃ }> ⟶ t'
let ⟨n₁, h₁⟩ := h₁ ht₁ t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht₁:t₁.IsValueh₁✝:t₁.IsValue → ∃ n, t₁ = Tm.const nn₁:Nath₁:t₁ = Tm.const n₁⊢ ∃ t', <{ if0 t₁ then t₂ else t₃ }> ⟶ t'
rw [h₁ t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht₁:t₁.IsValueh₁✝:t₁.IsValue → ∃ n, t₁ = Tm.const nn₁:Nath₁:t₁ = Tm.const n₁⊢ ∃ t', <{ if0 ~(Tm.const n₁) then t₂ else t₃ }> ⟶ t'] t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht₁:t₁.IsValueh₁✝:t₁.IsValue → ∃ n, t₁ = Tm.const nn₁:Nath₁:t₁ = Tm.const n₁⊢ ∃ t', <{ if0 ~(Tm.const n₁) then t₂ else t₃ }> ⟶ t'; cases n₁ zero t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht₁:t₁.IsValueh₁✝:t₁.IsValue → ∃ n, t₁ = Tm.const nh₁:t₁ = <{ 0 }>⊢ ∃ t', <{ if0 0 then t₂ else t₃ }> ⟶ t'succ t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht₁:t₁.IsValueh₁✝:t₁.IsValue → ∃ n, t₁ = Tm.const nn✝:Nath₁:t₁ = Tm.const (n✝ + 1)⊢ ∃ t', <{ if0 ~(Tm.const (n✝ + 1)) then t₂ else t₃ }> ⟶ t'
· zero t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht₁:t₁.IsValueh₁✝:t₁.IsValue → ∃ n, t₁ = Tm.const nh₁:t₁ = <{ 0 }>⊢ ∃ t', <{ if0 0 then t₂ else t₃ }> ⟶ t' exists t₂ zero t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht₁:t₁.IsValueh₁✝:t₁.IsValue → ∃ n, t₁ = Tm.const nh₁:t₁ = <{ 0 }>⊢ <{ if0 0 then t₂ else t₃ }> ⟶ t₂; apply_rules using ExtStlcEval All goals completed! 🐙
· succ t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht₁:t₁.IsValueh₁✝:t₁.IsValue → ∃ n, t₁ = Tm.const nn✝:Nath₁:t₁ = Tm.const (n✝ + 1)⊢ ∃ t', <{ if0 ~(Tm.const (n✝ + 1)) then t₂ else t₃ }> ⟶ t' exists t₃ succ t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht₁:t₁.IsValueh₁✝:t₁.IsValue → ∃ n, t₁ = Tm.const nn✝:Nath₁:t₁ = Tm.const (n✝ + 1)⊢ <{ if0 ~(Tm.const (n✝ + 1)) then t₂ else t₃ }> ⟶ t₃; apply_rules using ExtStlcEval All goals completed! 🐙
-- t₁ is not a value
case _ ht₁ => t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht₁:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ if0 t₁ then t₂ else t₃ }> ⟶ t'
obtain ⟨t₁', ht₁⟩ := ht₁ t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ ∃ t', <{ if0 t₁ then t₂ else t₃ }> ⟶ t'
exists <{if0 t₁' then t₂ else t₃}> t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ <{ if0 t₁ then t₂ else t₃ }> ⟶ <{ if0 t₁' then t₂ else t₃ }>; apply_rules using ExtStlcEval All goals completed! 🐙
| sumInl Γ t₁ τ₁ τ₂ h ih => sumInl t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'⊢ <{ inl τ₂ t₁ }>.IsValue ∨ ∃ t', <{ inl τ₂ t₁ }> ⟶ t'
cases ih rfl sumInl.inl t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'h✝:t₁.IsValue⊢ <{ inl τ₂ t₁ }>.IsValue ∨ ∃ t', <{ inl τ₂ t₁ }> ⟶ t'sumInl.inr t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'h✝:∃ t', t₁ ⟶ t'⊢ <{ inl τ₂ t₁ }>.IsValue ∨ ∃ t', <{ inl τ₂ t₁ }> ⟶ t'
-- t₁ is a value
case _ ht₁ => t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValue⊢ <{ inl τ₂ t₁ }>.IsValue ∨ ∃ t', <{ inl τ₂ t₁ }> ⟶ t'
left t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValue⊢ <{ inl τ₂ t₁ }>.IsValue; apply_rules using ExtStlcEval All goals completed! 🐙
-- t₁ is not a value
case _ ht₁ => t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:∃ t', t₁ ⟶ t'⊢ <{ inl τ₂ t₁ }>.IsValue ∨ ∃ t', <{ inl τ₂ t₁ }> ⟶ t'
obtain ⟨t₁', ht₁⟩ := ht₁ t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ <{ inl τ₂ t₁ }>.IsValue ∨ ∃ t', <{ inl τ₂ t₁ }> ⟶ t'
right t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ ∃ t', <{ inl τ₂ t₁ }> ⟶ t'; exists <{inl τ₂ t₁'}> t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ <{ inl τ₂ t₁ }> ⟶ <{ inl τ₂ t₁' }>; apply_rules using ExtStlcEval All goals completed! 🐙
| sumInr Γ t₂ τ₁ τ₂ h ih => sumInr t:Tmτ:TyΓ:Contextt₂:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'⊢ <{ inr τ₁ t₂ }>.IsValue ∨ ∃ t', <{ inr τ₁ t₂ }> ⟶ t'
cases ih rfl sumInr.inl t:Tmτ:TyΓ:Contextt₂:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'h✝:t₂.IsValue⊢ <{ inr τ₁ t₂ }>.IsValue ∨ ∃ t', <{ inr τ₁ t₂ }> ⟶ t'sumInr.inr t:Tmτ:TyΓ:Contextt₂:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'h✝:∃ t', t₂ ⟶ t'⊢ <{ inr τ₁ t₂ }>.IsValue ∨ ∃ t', <{ inr τ₁ t₂ }> ⟶ t'
-- t₁ is a value
case _ ht₁ => t:Tmτ:TyΓ:Contextt₂:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₂.IsValue⊢ <{ inr τ₁ t₂ }>.IsValue ∨ ∃ t', <{ inr τ₁ t₂ }> ⟶ t'
left t:Tmτ:TyΓ:Contextt₂:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₂.IsValue⊢ <{ inr τ₁ t₂ }>.IsValue; apply_rules using ExtStlcEval All goals completed! 🐙
-- t₁ is not a value
case _ ht₁ => t:Tmτ:TyΓ:Contextt₂:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:∃ t', t₂ ⟶ t'⊢ <{ inr τ₁ t₂ }>.IsValue ∨ ∃ t', <{ inr τ₁ t₂ }> ⟶ t'
obtain ⟨t₂', ht₁⟩ := ht₁ t:Tmτ:TyΓ:Contextt₂:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₂':Tmht₁:t₂ ⟶ t₂'⊢ <{ inr τ₁ t₂ }>.IsValue ∨ ∃ t', <{ inr τ₁ t₂ }> ⟶ t'
right t:Tmτ:TyΓ:Contextt₂:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₂':Tmht₁:t₂ ⟶ t₂'⊢ ∃ t', <{ inr τ₁ t₂ }> ⟶ t'; exists <{inr τ₁ t₂'}> t:Tmτ:TyΓ:Contextt₂:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₂':Tmht₁:t₂ ⟶ t₂'⊢ <{ inr τ₁ t₂ }> ⟶ <{ inr τ₁ t₂' }>; apply_rules using ExtStlcEval All goals completed! 🐙
| sumCase Γ x₁ x₂ τ₁ τ₂ τ₃ t t₁ t₂ h₁ h₂ h₃ ih₁ ih₂ ih₃ => sumCase t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'⊢ <{ case t of inl~x₁ => t₁ | inr~x₂ => t₂ }>.IsValue ∨ ∃ t', <{ case t of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t'
right sumCase t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'⊢ ∃ t', <{ case t of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t'; cases ih₁ rfl sumCase.inl t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'h✝:t.IsValue⊢ ∃ t', <{ case t of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t'sumCase.inr t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'h✝:∃ t', t ⟶ t'⊢ ∃ t', <{ case t of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t'
-- t₁ is a value
case _ ht => t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht:t.IsValue⊢ ∃ t', <{ case t of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t'
apply canonical_forms_sum at h₁ t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht:t.IsValueh₁:t.IsValue → ∃ v, v.IsValue ∧ (t = <{ inl τ₂ v }> ∨ t = <{ inr τ₁ v }>)⊢ ∃ t', <{ case t of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t'
obtain ⟨v, hv, hl | hr⟩ := h₁ ht inl t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht:t.IsValueh₁:t.IsValue → ∃ v, v.IsValue ∧ (t = <{ inl τ₂ v }> ∨ t = <{ inr τ₁ v }>)v:Tmhv:v.IsValuehl:t = <{ inl τ₂ v }>⊢ ∃ t', <{ case t of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t'inr t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht:t.IsValueh₁:t.IsValue → ∃ v, v.IsValue ∧ (t = <{ inl τ₂ v }> ∨ t = <{ inr τ₁ v }>)v:Tmhv:v.IsValuehr:t = <{ inr τ₁ v }>⊢ ∃ t', <{ case t of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t'
· inl t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht:t.IsValueh₁:t.IsValue → ∃ v, v.IsValue ∧ (t = <{ inl τ₂ v }> ∨ t = <{ inr τ₁ v }>)v:Tmhv:v.IsValuehl:t = <{ inl τ₂ v }>⊢ ∃ t', <{ case t of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t' rw [hl inl t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht:t.IsValueh₁:t.IsValue → ∃ v, v.IsValue ∧ (t = <{ inl τ₂ v }> ∨ t = <{ inr τ₁ v }>)v:Tmhv:v.IsValuehl:t = <{ inl τ₂ v }>⊢ ∃ t', <{ case inl τ₂ v of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t'] inl t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht:t.IsValueh₁:t.IsValue → ∃ v, v.IsValue ∧ (t = <{ inl τ₂ v }> ∨ t = <{ inr τ₁ v }>)v:Tmhv:v.IsValuehl:t = <{ inl τ₂ v }>⊢ ∃ t', <{ case inl τ₂ v of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t'; exists <{ [x₁ := v] t₁ }> inl t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht:t.IsValueh₁:t.IsValue → ∃ v, v.IsValue ∧ (t = <{ inl τ₂ v }> ∨ t = <{ inr τ₁ v }>)v:Tmhv:v.IsValuehl:t = <{ inl τ₂ v }>⊢ <{ case inl τ₂ v of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ <{ [~x₁ := v] t₁ }>; apply_rules using ExtStlcEval All goals completed! 🐙
· inr t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht:t.IsValueh₁:t.IsValue → ∃ v, v.IsValue ∧ (t = <{ inl τ₂ v }> ∨ t = <{ inr τ₁ v }>)v:Tmhv:v.IsValuehr:t = <{ inr τ₁ v }>⊢ ∃ t', <{ case t of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t' rw [hr inr t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht:t.IsValueh₁:t.IsValue → ∃ v, v.IsValue ∧ (t = <{ inl τ₂ v }> ∨ t = <{ inr τ₁ v }>)v:Tmhv:v.IsValuehr:t = <{ inr τ₁ v }>⊢ ∃ t', <{ case inr τ₁ v of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t'] inr t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht:t.IsValueh₁:t.IsValue → ∃ v, v.IsValue ∧ (t = <{ inl τ₂ v }> ∨ t = <{ inr τ₁ v }>)v:Tmhv:v.IsValuehr:t = <{ inr τ₁ v }>⊢ ∃ t', <{ case inr τ₁ v of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t'; exists <{ [x₂ := v] t₂ }> inr t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht:t.IsValueh₁:t.IsValue → ∃ v, v.IsValue ∧ (t = <{ inl τ₂ v }> ∨ t = <{ inr τ₁ v }>)v:Tmhv:v.IsValuehr:t = <{ inr τ₁ v }>⊢ <{ case inr τ₁ v of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ <{ [~x₂ := v] t₂ }>; apply_rules using ExtStlcEval All goals completed! 🐙
-- t₁ is not a value
case _ ht => t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht:∃ t', t ⟶ t'⊢ ∃ t', <{ case t of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t'
obtain ⟨t', ht⟩ := ht t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't':Tmht:t ⟶ t'⊢ ∃ t', <{ case t of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t'
exists <{case t' of inl x₁ => t₁ | inr x₂ => t₂}> t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ih₂:∅ = x₁ →ₚ τ₁ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₃:∅ = x₂ →ₚ τ₂ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't':Tmht:t ⟶ t'⊢ <{ case t of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ <{ case t' of inl~x₁ => t₁ | inr~x₂ => t₂ }>; apply_rules using ExtStlcEval All goals completed! 🐙
| listCons Γ t₁ t₂ τ₁ h₁ h₂ ih₁ ih₂ => listCons t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ [ τ₁ ] }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'⊢ <{ t₁ :: t₂ }>.IsValue ∨ ∃ t', <{ t₁ :: t₂ }> ⟶ t'
cases ih₁ rfl listCons.inl t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ [ τ₁ ] }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'h✝:t₁.IsValue⊢ <{ t₁ :: t₂ }>.IsValue ∨ ∃ t', <{ t₁ :: t₂ }> ⟶ t'listCons.inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ [ τ₁ ] }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'h✝:∃ t', t₁ ⟶ t'⊢ <{ t₁ :: t₂ }>.IsValue ∨ ∃ t', <{ t₁ :: t₂ }> ⟶ t'
-- t₁ is a value
case _ ht₁ => t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ [ τ₁ ] }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValue⊢ <{ t₁ :: t₂ }>.IsValue ∨ ∃ t', <{ t₁ :: t₂ }> ⟶ t'
cases ih₂ rfl inl t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ [ τ₁ ] }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueh✝:t₂.IsValue⊢ <{ t₁ :: t₂ }>.IsValue ∨ ∃ t', <{ t₁ :: t₂ }> ⟶ t'inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ [ τ₁ ] }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueh✝:∃ t', t₂ ⟶ t'⊢ <{ t₁ :: t₂ }>.IsValue ∨ ∃ t', <{ t₁ :: t₂ }> ⟶ t'
-- t₂ is a value
case _ ht₂ => t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ [ τ₁ ] }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:t₂.IsValue⊢ <{ t₁ :: t₂ }>.IsValue ∨ ∃ t', <{ t₁ :: t₂ }> ⟶ t'
left t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ [ τ₁ ] }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:t₂.IsValue⊢ <{ t₁ :: t₂ }>.IsValue; apply_rules using ExtStlcEval All goals completed! 🐙
-- t₂ is not a value
case _ ht₂ => t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ [ τ₁ ] }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:∃ t', t₂ ⟶ t'⊢ <{ t₁ :: t₂ }>.IsValue ∨ ∃ t', <{ t₁ :: t₂ }> ⟶ t'
obtain ⟨t₂', ht₂⟩ := ht₂ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ [ τ₁ ] }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValuet₂':Tmht₂:t₂ ⟶ t₂'⊢ <{ t₁ :: t₂ }>.IsValue ∨ ∃ t', <{ t₁ :: t₂ }> ⟶ t'
right t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ [ τ₁ ] }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValuet₂':Tmht₂:t₂ ⟶ t₂'⊢ ∃ t', <{ t₁ :: t₂ }> ⟶ t'; exists <{t₁ :: t₂'}> t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ [ τ₁ ] }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValuet₂':Tmht₂:t₂ ⟶ t₂'⊢ <{ t₁ :: t₂ }> ⟶ <{ t₁ :: t₂' }>; apply_rules using ExtStlcEval All goals completed! 🐙
-- t₁ is not a value
case _ ht₁ => t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ [ τ₁ ] }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:∃ t', t₁ ⟶ t'⊢ <{ t₁ :: t₂ }>.IsValue ∨ ∃ t', <{ t₁ :: t₂ }> ⟶ t'
obtain ⟨t₁', ht₁⟩ := ht₁ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ [ τ₁ ] }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ <{ t₁ :: t₂ }>.IsValue ∨ ∃ t', <{ t₁ :: t₂ }> ⟶ t'
right t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ [ τ₁ ] }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ ∃ t', <{ t₁ :: t₂ }> ⟶ t'; exists <{t₁' :: t₂}> t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ [ τ₁ ] }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ <{ t₁ :: t₂ }> ⟶ <{ t₁' :: t₂ }>; apply_rules using ExtStlcEval All goals completed! 🐙
| listCase Γ t₁ t₂ t₃ x₁ x₂ τ₁ τ₂ h₁ h₂ h₃ ih₁ ih₂ ih₃ => listCase t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'⊢ <{ case t₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }>.IsValue ∨ ∃ t', <{ case t₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t'
right listCase t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'⊢ ∃ t', <{ case t₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t'; cases ih₁ rfl listCase.inl t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'h✝:t₁.IsValue⊢ ∃ t', <{ case t₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t'listCase.inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'h✝:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ case t₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t'
-- t₁ is a value
case _ ht => t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht:t₁.IsValue⊢ ∃ t', <{ case t₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t'
apply canonical_forms_list at h₁ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht:t₁.IsValueh₁:t₁.IsValue → t₁ = <{ nil τ₁ }> ∨ ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t₁ = <{ v₁ :: v₂ }>⊢ ∃ t', <{ case t₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t'
obtain hnil | ⟨v₁, v₂, hv₁, hv₂, h⟩ := h₁ ht inl t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht:t₁.IsValueh₁:t₁.IsValue → t₁ = <{ nil τ₁ }> ∨ ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t₁ = <{ v₁ :: v₂ }>hnil:t₁ = <{ nil τ₁ }>⊢ ∃ t', <{ case t₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t'inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht:t₁.IsValueh₁:t₁.IsValue → t₁ = <{ nil τ₁ }> ∨ ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t₁ = <{ v₁ :: v₂ }>v₁:Tmv₂:Tmhv₁:v₁.IsValuehv₂:v₂.IsValueh:t₁ = <{ v₁ :: v₂ }>⊢ ∃ t', <{ case t₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t'
· inl t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht:t₁.IsValueh₁:t₁.IsValue → t₁ = <{ nil τ₁ }> ∨ ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t₁ = <{ v₁ :: v₂ }>hnil:t₁ = <{ nil τ₁ }>⊢ ∃ t', <{ case t₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t' rw [hnil inl t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht:t₁.IsValueh₁:t₁.IsValue → t₁ = <{ nil τ₁ }> ∨ ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t₁ = <{ v₁ :: v₂ }>hnil:t₁ = <{ nil τ₁ }>⊢ ∃ t', <{ case nil τ₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t'] inl t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht:t₁.IsValueh₁:t₁.IsValue → t₁ = <{ nil τ₁ }> ∨ ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t₁ = <{ v₁ :: v₂ }>hnil:t₁ = <{ nil τ₁ }>⊢ ∃ t', <{ case nil τ₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t'; exists t₂ inl t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht:t₁.IsValueh₁:t₁.IsValue → t₁ = <{ nil τ₁ }> ∨ ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t₁ = <{ v₁ :: v₂ }>hnil:t₁ = <{ nil τ₁ }>⊢ <{ case nil τ₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t₂; apply_rules using ExtStlcEval All goals completed! 🐙
· inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht:t₁.IsValueh₁:t₁.IsValue → t₁ = <{ nil τ₁ }> ∨ ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t₁ = <{ v₁ :: v₂ }>v₁:Tmv₂:Tmhv₁:v₁.IsValuehv₂:v₂.IsValueh:t₁ = <{ v₁ :: v₂ }>⊢ ∃ t', <{ case t₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t' rw [h inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht:t₁.IsValueh₁:t₁.IsValue → t₁ = <{ nil τ₁ }> ∨ ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t₁ = <{ v₁ :: v₂ }>v₁:Tmv₂:Tmhv₁:v₁.IsValuehv₂:v₂.IsValueh:t₁ = <{ v₁ :: v₂ }>⊢ ∃ t', <{ case v₁ :: v₂ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t'] inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht:t₁.IsValueh₁:t₁.IsValue → t₁ = <{ nil τ₁ }> ∨ ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t₁ = <{ v₁ :: v₂ }>v₁:Tmv₂:Tmhv₁:v₁.IsValuehv₂:v₂.IsValueh:t₁ = <{ v₁ :: v₂ }>⊢ ∃ t', <{ case v₁ :: v₂ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t'; exists <{ [x₂ := v₂] [x₁ := v₁] t₃ }> inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht:t₁.IsValueh₁:t₁.IsValue → t₁ = <{ nil τ₁ }> ∨ ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t₁ = <{ v₁ :: v₂ }>v₁:Tmv₂:Tmhv₁:v₁.IsValuehv₂:v₂.IsValueh:t₁ = <{ v₁ :: v₂ }>⊢ <{ case v₁ :: v₂ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ <{ [~x₂ := v₂] [~x₁ := v₁] t₃ }>; apply_rules using ExtStlcEval All goals completed! 🐙
-- t₁ is not a value
case _ ht => t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'ht:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ case t₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t'
obtain ⟨t', ht⟩ := ht t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t't':Tmht:t₁ ⟶ t'⊢ ∃ t', <{ case t₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t'
exists <{case t' of nil => t₂ | x₁ :: x₂ => t₃}> t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t't':Tmht:t₁ ⟶ t'⊢ <{ case t₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ <{ case t' of nil => t₂ | ~x₁ :: ~x₂ => t₃ }>; apply_rules using ExtStlcEval All goals completed! 🐙
-- complete the proof
| pair Γ t₁ t₂ τ₁ τ₂ h₁ h₂ ih₁ ih₂ => pair t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'⊢ <{ ( t₁ , t₂ ) }>.IsValue ∨ ∃ t', <{ ( t₁ , t₂ ) }> ⟶ t'
cases ih₁ rfl pair.inl t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'h✝:t₁.IsValue⊢ <{ ( t₁ , t₂ ) }>.IsValue ∨ ∃ t', <{ ( t₁ , t₂ ) }> ⟶ t'pair.inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'h✝:∃ t', t₁ ⟶ t'⊢ <{ ( t₁ , t₂ ) }>.IsValue ∨ ∃ t', <{ ( t₁ , t₂ ) }> ⟶ t'
-- t₁ is a value
case _ ht₁ => t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValue⊢ <{ ( t₁ , t₂ ) }>.IsValue ∨ ∃ t', <{ ( t₁ , t₂ ) }> ⟶ t'
cases ih₂ rfl inl t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueh✝:t₂.IsValue⊢ <{ ( t₁ , t₂ ) }>.IsValue ∨ ∃ t', <{ ( t₁ , t₂ ) }> ⟶ t'inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueh✝:∃ t', t₂ ⟶ t'⊢ <{ ( t₁ , t₂ ) }>.IsValue ∨ ∃ t', <{ ( t₁ , t₂ ) }> ⟶ t'
-- t₂ is a value
case _ ht₂ => t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:t₂.IsValue⊢ <{ ( t₁ , t₂ ) }>.IsValue ∨ ∃ t', <{ ( t₁ , t₂ ) }> ⟶ t'
left t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:t₂.IsValue⊢ <{ ( t₁ , t₂ ) }>.IsValue; apply_rules using ExtStlcEval All goals completed! 🐙
-- t₂ is not a value
case _ ht₂ => t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValueht₂:∃ t', t₂ ⟶ t'⊢ <{ ( t₁ , t₂ ) }>.IsValue ∨ ∃ t', <{ ( t₁ , t₂ ) }> ⟶ t'
obtain ⟨t₂', ht₂⟩ := ht₂ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValuet₂':Tmht₂:t₂ ⟶ t₂'⊢ <{ ( t₁ , t₂ ) }>.IsValue ∨ ∃ t', <{ ( t₁ , t₂ ) }> ⟶ t'
right t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValuet₂':Tmht₂:t₂ ⟶ t₂'⊢ ∃ t', <{ ( t₁ , t₂ ) }> ⟶ t'; exists <{(t₁, t₂')}> t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValuet₂':Tmht₂:t₂ ⟶ t₂'⊢ <{ ( t₁ , t₂ ) }> ⟶ <{ ( t₁ , t₂' ) }>; apply_rules using ExtStlcEval All goals completed! 🐙
-- t₁ is not a value
case _ ht₁ => t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:∃ t', t₁ ⟶ t'⊢ <{ ( t₁ , t₂ ) }>.IsValue ∨ ∃ t', <{ ( t₁ , t₂ ) }> ⟶ t'
obtain ⟨t₁', ht₁⟩ := ht₁ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ <{ ( t₁ , t₂ ) }>.IsValue ∨ ∃ t', <{ ( t₁ , t₂ ) }> ⟶ t'
right t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ ∃ t', <{ ( t₁ , t₂ ) }> ⟶ t'; exists <{(t₁', t₂)}> t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ <{ ( t₁ , t₂ ) }> ⟶ <{ ( t₁' , t₂ ) }>; apply_rules using ExtStlcEval All goals completed! 🐙
| fst Γ t τ₁ τ₂ h ih => fst t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>ih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'⊢ <{ fst t }>.IsValue ∨ ∃ t', <{ fst t }> ⟶ t'
right fst t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>ih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'⊢ ∃ t', <{ fst t }> ⟶ t'; cases ih rfl fst.inl t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>ih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'h✝:t.IsValue⊢ ∃ t', <{ fst t }> ⟶ t'fst.inr t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>ih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'h✝:∃ t', t ⟶ t'⊢ ∃ t', <{ fst t }> ⟶ t'
-- t₁ is a value
case _ ht₁ => t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>ih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ht₁:t.IsValue⊢ ∃ t', <{ fst t }> ⟶ t'
apply canonical_forms_prod at h t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ht₁:t.IsValueh:t.IsValue → ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t = <{ ( v₁ , v₂ ) }>⊢ ∃ t', <{ fst t }> ⟶ t'
obtain ⟨v₁, v₂, hv₁, hv₂, ht⟩ := h ht₁ t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ht₁:t.IsValueh:t.IsValue → ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t = <{ ( v₁ , v₂ ) }>v₁:Tmv₂:Tmhv₁:v₁.IsValuehv₂:v₂.IsValueht:t = <{ ( v₁ , v₂ ) }>⊢ ∃ t', <{ fst t }> ⟶ t'; rw [ht t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ht₁:t.IsValueh:t.IsValue → ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t = <{ ( v₁ , v₂ ) }>v₁:Tmv₂:Tmhv₁:v₁.IsValuehv₂:v₂.IsValueht:t = <{ ( v₁ , v₂ ) }>⊢ ∃ t', <{ fst ( v₁ , v₂ ) }> ⟶ t'] t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ht₁:t.IsValueh:t.IsValue → ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t = <{ ( v₁ , v₂ ) }>v₁:Tmv₂:Tmhv₁:v₁.IsValuehv₂:v₂.IsValueht:t = <{ ( v₁ , v₂ ) }>⊢ ∃ t', <{ fst ( v₁ , v₂ ) }> ⟶ t'
exists v₁ t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ht₁:t.IsValueh:t.IsValue → ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t = <{ ( v₁ , v₂ ) }>v₁:Tmv₂:Tmhv₁:v₁.IsValuehv₂:v₂.IsValueht:t = <{ ( v₁ , v₂ ) }>⊢ <{ fst ( v₁ , v₂ ) }> ⟶ v₁; apply_rules using ExtStlcEval All goals completed! 🐙
-- t₁ is not a value
case _ ht₁ => t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>ih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ht₁:∃ t', t ⟶ t'⊢ ∃ t', <{ fst t }> ⟶ t'
obtain ⟨t₁', ht₁⟩ := ht₁ t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>ih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t't₁':Tmht₁:t ⟶ t₁'⊢ ∃ t', <{ fst t }> ⟶ t'
exists <{fst t₁'}> t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>ih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t't₁':Tmht₁:t ⟶ t₁'⊢ <{ fst t }> ⟶ <{ fst t₁' }>; apply_rules using ExtStlcEval All goals completed! 🐙
| snd Γ t τ₁ τ₂ h ih => snd t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>ih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'⊢ <{ snd t }>.IsValue ∨ ∃ t', <{ snd t }> ⟶ t'
right snd t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>ih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'⊢ ∃ t', <{ snd t }> ⟶ t'; cases ih rfl snd.inl t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>ih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'h✝:t.IsValue⊢ ∃ t', <{ snd t }> ⟶ t'snd.inr t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>ih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'h✝:∃ t', t ⟶ t'⊢ ∃ t', <{ snd t }> ⟶ t'
-- t₁ is a value
case _ ht₁ => t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>ih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ht₁:t.IsValue⊢ ∃ t', <{ snd t }> ⟶ t'
apply canonical_forms_prod at h t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ht₁:t.IsValueh:t.IsValue → ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t = <{ ( v₁ , v₂ ) }>⊢ ∃ t', <{ snd t }> ⟶ t'
obtain ⟨v₁, v₂, hv₁, hv₂, ht⟩ := h ht₁ t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ht₁:t.IsValueh:t.IsValue → ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t = <{ ( v₁ , v₂ ) }>v₁:Tmv₂:Tmhv₁:v₁.IsValuehv₂:v₂.IsValueht:t = <{ ( v₁ , v₂ ) }>⊢ ∃ t', <{ snd t }> ⟶ t'; rw [ht t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ht₁:t.IsValueh:t.IsValue → ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t = <{ ( v₁ , v₂ ) }>v₁:Tmv₂:Tmhv₁:v₁.IsValuehv₂:v₂.IsValueht:t = <{ ( v₁ , v₂ ) }>⊢ ∃ t', <{ snd ( v₁ , v₂ ) }> ⟶ t'] t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ht₁:t.IsValueh:t.IsValue → ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t = <{ ( v₁ , v₂ ) }>v₁:Tmv₂:Tmhv₁:v₁.IsValuehv₂:v₂.IsValueht:t = <{ ( v₁ , v₂ ) }>⊢ ∃ t', <{ snd ( v₁ , v₂ ) }> ⟶ t'
exists v₂ t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ht₁:t.IsValueh:t.IsValue → ∃ v₁ v₂, v₁.IsValue ∧ v₂.IsValue ∧ t = <{ ( v₁ , v₂ ) }>v₁:Tmv₂:Tmhv₁:v₁.IsValuehv₂:v₂.IsValueht:t = <{ ( v₁ , v₂ ) }>⊢ <{ snd ( v₁ , v₂ ) }> ⟶ v₂; apply_rules using ExtStlcEval All goals completed! 🐙
-- t₁ is not a value
case _ ht₁ => t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>ih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t'ht₁:∃ t', t ⟶ t'⊢ ∃ t', <{ snd t }> ⟶ t'
obtain ⟨t₁', ht₁⟩ := ht₁ t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>ih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t't₁':Tmht₁:t ⟶ t₁'⊢ ∃ t', <{ snd t }> ⟶ t'
exists <{snd t₁'}> t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>ih:∅ = ∅ → t.IsValue ∨ ∃ t', t ⟶ t't₁':Tmht₁:t ⟶ t₁'⊢ <{ snd t }> ⟶ <{ snd t₁' }>; apply_rules using ExtStlcEval All goals completed! 🐙
| letIn Γ x t₁ t₂ τ₁ τ₂ h₁ h₂ ih₁ ih₂ => letIn t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = x →ₚ τ₁ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'⊢ <{ let ~x = t₁ in t₂ }>.IsValue ∨ ∃ t', <{ let ~x = t₁ in t₂ }> ⟶ t'
right letIn t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = x →ₚ τ₁ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'⊢ ∃ t', <{ let ~x = t₁ in t₂ }> ⟶ t'; cases ih₁ rfl letIn.inl t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = x →ₚ τ₁ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'h✝:t₁.IsValue⊢ ∃ t', <{ let ~x = t₁ in t₂ }> ⟶ t'letIn.inr t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = x →ₚ τ₁ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'h✝:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ let ~x = t₁ in t₂ }> ⟶ t'
-- t₁ is a value
case _ ht₁ => t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = x →ₚ τ₁ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValue⊢ ∃ t', <{ let ~x = t₁ in t₂ }> ⟶ t'
exists <{ [x := t₁] t₂ }> t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = x →ₚ τ₁ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:t₁.IsValue⊢ <{ let ~x = t₁ in t₂ }> ⟶ <{ [~x := t₁] t₂ }>; apply_rules using ExtStlcEval All goals completed! 🐙
-- t₁ is not a value
case _ ht₁ => t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = x →ₚ τ₁ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ht₁:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ let ~x = t₁ in t₂ }> ⟶ t'
obtain ⟨t₁', ht₁⟩ := ht₁ t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = x →ₚ τ₁ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ ∃ t', <{ let ~x = t₁ in t₂ }> ⟶ t'
exists <{let x = t₁' in t₂}> t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = x →ₚ τ₁ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ <{ let ~x = t₁ in t₂ }> ⟶ <{ let ~x = t₁' in t₂ }>; apply_rules using ExtStlcEval All goals completed! 🐙
| fix Γ t₁ τ₁ h ih => fix t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ → τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'⊢ <{ fix t₁ }>.IsValue ∨ ∃ t', <{ fix t₁ }> ⟶ t'
right fix t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ → τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'⊢ ∃ t', <{ fix t₁ }> ⟶ t'; cases ih rfl fix.inl t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ → τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'h✝:t₁.IsValue⊢ ∃ t', <{ fix t₁ }> ⟶ t'fix.inr t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ → τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'h✝:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ fix t₁ }> ⟶ t'
-- t₁ is a value
case _ ht₁ => t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ → τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValue⊢ ∃ t', <{ fix t₁ }> ⟶ t'
apply canonical_forms_fun at h t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValueh:t₁.IsValue → ∃ x u, t₁ = <{ λ ~x : τ₁ . u }>⊢ ∃ t', <{ fix t₁ }> ⟶ t'
obtain ⟨x, v, ht⟩ := h ht₁ t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValueh:t₁.IsValue → ∃ x u, t₁ = <{ λ ~x : τ₁ . u }>x:Stringv:Tmht:t₁ = <{ λ ~x : τ₁ . v }>⊢ ∃ t', <{ fix t₁ }> ⟶ t'; rw [ht t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValueh:t₁.IsValue → ∃ x u, t₁ = <{ λ ~x : τ₁ . u }>x:Stringv:Tmht:t₁ = <{ λ ~x : τ₁ . v }>⊢ ∃ t', <{ fix (λ ~x : τ₁ . v) }> ⟶ t'] t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValueh:t₁.IsValue → ∃ x u, t₁ = <{ λ ~x : τ₁ . u }>x:Stringv:Tmht:t₁ = <{ λ ~x : τ₁ . v }>⊢ ∃ t', <{ fix (λ ~x : τ₁ . v) }> ⟶ t'
exists <{ [x := fix (λ x : τ₁ . v) ] v }> t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:t₁.IsValueh:t₁.IsValue → ∃ x u, t₁ = <{ λ ~x : τ₁ . u }>x:Stringv:Tmht:t₁ = <{ λ ~x : τ₁ . v }>⊢ <{ fix (λ ~x : τ₁ . v) }> ⟶ <{ [~x := fix (λ ~x : τ₁ . v)] v }>; apply_rules using ExtStlcEval All goals completed! 🐙
-- t₁ is not a value
case _ ht₁ => t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ → τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ht₁:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ fix t₁ }> ⟶ t'
obtain ⟨t₁', ht₁⟩ := ht₁ t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ → τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ ∃ t', <{ fix t₁ }> ⟶ t'
exists <{fix t₁'}> t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ → τ₁ }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmht₁:t₁ ⟶ t₁'⊢ <{ fix t₁ }> ⟶ <{ fix t₁' }>; apply_rules using ExtStlcEval All goals completed! 🐙
Through the power of automation, the weakening proof is exactly the same as for the original STLC.
theorem weakening {Γ Γ' : Context} {t : Tm} {τ: Ty}
(hi : Γ ⊆ Γ')
(ht : <{ Γ ⊢ t ⦂ τ }>) :
<{ Γ' ⊢ t ⦂ τ }> := by Γ:ContextΓ':Contextt:Tmτ:Tyhi:Γ ⊆ Γ'ht:<{ Γ ⊢ t ⦂ τ }>⊢ <{ Γ' ⊢ t ⦂ τ }>
induction ht generalizing Γ' with (apply_rules [PartialMap.update_subset] using ExtStlcTyping All goals completed! 🐙)
theorem weakening_empty {Γ : Context} {t : Tm} {τ: Ty}
(ht :<{ ∅ ⊢ t ⦂ τ }>) :
<{ Γ ⊢ t ⦂ τ }> := by Γ:Contextt:Tmτ:Tyht:<{ ∅ ⊢ t ⦂ τ }>⊢ <{ Γ ⊢ t ⦂ τ }>
apply weakening _ ht Γ:Contextt:Tmτ:Tyht:<{ ∅ ⊢ t ⦂ τ }>⊢ ∅ ⊆ Γ
intro _ _ h Γ:Contextt:Tmτ:Tyht:<{ ∅ ⊢ t ⦂ τ }>a✝:Stringb✝:Tyh:∅[a✝] = some b✝⊢ Γ[a✝] = some b✝
rw [PartialMap.getElem_empty Γ:Contextt:Tmτ:Tyht:<{ ∅ ⊢ t ⦂ τ }>a✝:Stringb✝:Tyh:none = some b✝⊢ Γ[a✝] = some b✝] at h Γ:Contextt:Tmτ:Tyht:<{ ∅ ⊢ t ⦂ τ }>a✝:Stringb✝:Tyh:none = some b✝⊢ Γ[a✝] = some b✝
contradiction All goals completed! 🐙
Complete the proof of substitution_preserves_typing
theorem substitution_preserves_typing (Γ : Context) (x : String) (τ₁ : Ty) (t v : Tm) (τ : Ty)
(ht : <{ x ↦ τ₁ ; Γ ⊢ t ⦂ τ }>)
(hv : <{ ∅ ⊢ v ⦂ τ₁ }>) :
<{ Γ ⊢ [x := v] t ⦂ τ }> := by Γ:Contextx:Stringτ₁:Tyt:Tmv:Tmτ:Tyht:<{ ~(x →ₚ τ₁ ; Γ) ⊢ t ⦂ τ }>hv:<{ ∅ ⊢ v ⦂ τ₁ }>⊢ <{ Γ ⊢ [~x := v] t ⦂ τ }>
solution!
induction t generalizing Γ τ with (
rw [subst var x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:StringΓ:Contextτ:Tyht:<{ ~(x →ₚ τ₁ ; Γ) ⊢ ~(StlcExtended.Tm.var y) ⦂ τ }>⊢ <{ Γ ⊢ ~(if x = y then v else StlcExtended.Tm.var y) ⦂ τ }>] snd x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝:Tma_ih✝:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyht:<{ ~(x →ₚ τ₁ ; Γ) ⊢ snd a✝ ⦂ τ }>⊢ <{ Γ ⊢ snd [~x := v] a✝ ⦂ τ }> fix x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝:Tma_ih✝:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyht:<{ ~(x →ₚ τ₁ ; Γ) ⊢ fix a✝ ⦂ τ }>⊢ <{ Γ ⊢ fix [~x := v] a✝ ⦂ τ }>; try (inversion ht fix x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝¹:Tma_ih✝:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tya✝:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ → τ }>⊢ <{ Γ ⊢ fix [~x := v] a✝ ⦂ τ }>; apply_rules using ExtStlcTyping All goals completed! 🐙; done All goals completed! 🐙))
| var y => var x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:StringΓ:Contextτ:Tyht:<{ ~(x →ₚ τ₁ ; Γ) ⊢ ~(StlcExtended.Tm.var y) ⦂ τ }>⊢ <{ Γ ⊢ ~(if x = y then v else StlcExtended.Tm.var y) ⦂ τ }>
inversion ht with | _ h =>
by_cases h₁ : x = y pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ₁ ; Γ)[y] = some τh₁:x = y⊢ <{ Γ ⊢ ~(if x = y then v else StlcExtended.Tm.var y) ⦂ τ }>neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ₁ ; Γ)[y] = some τh₁:¬x = y⊢ <{ Γ ⊢ ~(if x = y then v else StlcExtended.Tm.var y) ⦂ τ }>
· pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ₁ ; Γ)[y] = some τh₁:x = y⊢ <{ Γ ⊢ ~(if x = y then v else StlcExtended.Tm.var y) ⦂ τ }> subst h₁ pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>Γ:Contextτ:Tyh:(x →ₚ τ₁ ; Γ)[x] = some τ⊢ <{ Γ ⊢ ~(if x = x then v else StlcExtended.Tm.var x) ⦂ τ }>; simp at h pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>Γ:Contextτ:Tyh:τ₁ = τ⊢ <{ Γ ⊢ ~(if x = x then v else StlcExtended.Tm.var x) ⦂ τ }>; subst h pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>Γ:Context⊢ <{ Γ ⊢ ~(if x = x then v else StlcExtended.Tm.var x) ⦂ τ₁ }>;
apply weakening_empty at hv pos x:Stringτ₁:Tyv:Tmhv✝:<{ ∅ ⊢ v ⦂ τ₁ }>Γ:Contexthv:<{ ~?Γ ⊢ v ⦂ τ₁ }>⊢ <{ Γ ⊢ ~(if x = x then v else StlcExtended.Tm.var x) ⦂ τ₁ }>Γ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>Γ:Context⊢ Context
simp pos x:Stringτ₁:Tyv:Tmhv✝:<{ ∅ ⊢ v ⦂ τ₁ }>Γ:Contexthv:<{ ~?Γ ⊢ v ⦂ τ₁ }>⊢ <{ Γ ⊢ v ⦂ τ₁ }>Γ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>Γ:Context⊢ Context; assumption All goals completed! 🐙
· neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ₁ ; Γ)[y] = some τh₁:¬x = y⊢ <{ Γ ⊢ ~(if x = y then v else StlcExtended.Tm.var y) ⦂ τ }> rw [PartialMap.update_neq neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τh₁:¬x = y⊢ <{ Γ ⊢ ~(if x = y then v else StlcExtended.Tm.var y) ⦂ τ }>neg.h x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ₁ ; Γ)[y] = some τh₁:¬x = y⊢ x ≠ y] at h neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τh₁:¬x = y⊢ <{ Γ ⊢ ~(if x = y then v else StlcExtended.Tm.var y) ⦂ τ }>neg.h x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ₁ ; Γ)[y] = some τh₁:¬x = y⊢ x ≠ y <;> neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τh₁:¬x = y⊢ <{ Γ ⊢ ~(if x = y then v else StlcExtended.Tm.var y) ⦂ τ }>neg.h x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ₁ ; Γ)[y] = some τh₁:¬x = y⊢ x ≠ y simp_all All goals completed! 🐙
apply_rules using ExtStlcTyping All goals completed! 🐙
| abs y _ _ ih => abs x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tya✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyht:<{ ~(x →ₚ τ₁ ; Γ) ⊢ λ ~y : a✝¹ . a✝ ⦂ τ }>⊢ <{ Γ ⊢ ~(if x = y then <{ λ ~y : a✝¹ . a✝ }> else <{ λ ~y : a✝¹ . [~x := v] a✝ }>) ⦂ τ }>
inversion ht with | _ h =>
by_cases h₁ : x = y pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tya✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ₁✝:Tyh:<{ ~(y →ₚ a✝¹ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ₁✝ }>h₁:x = y⊢ <{ Γ ⊢ ~(if x = y then <{ λ ~y : a✝¹ . a✝ }> else <{ λ ~y : a✝¹ . [~x := v] a✝ }>) ⦂ a✝¹ → τ₁✝ }>neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tya✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ₁✝:Tyh:<{ ~(y →ₚ a✝¹ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ₁✝ }>h₁:¬x = y⊢ <{ Γ ⊢ ~(if x = y then <{ λ ~y : a✝¹ . a✝ }> else <{ λ ~y : a✝¹ . [~x := v] a✝ }>) ⦂ a✝¹ → τ₁✝ }>
· pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tya✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ₁✝:Tyh:<{ ~(y →ₚ a✝¹ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ₁✝ }>h₁:x = y⊢ <{ Γ ⊢ ~(if x = y then <{ λ ~y : a✝¹ . a✝ }> else <{ λ ~y : a✝¹ . [~x := v] a✝ }>) ⦂ a✝¹ → τ₁✝ }> simp_all [PartialMap.update_shadow] pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tya✝:TmΓ:Contextτ₁✝:Tyih:∀ (Γ : Context) (τ : Ty), <{ ~(y →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~y := v] a✝ ⦂ τ }>h:<{ ~(y →ₚ a✝¹ ; Γ) ⊢ a✝ ⦂ τ₁✝ }>h₁:x = y⊢ <{ Γ ⊢ λ ~y : a✝¹ . a✝ ⦂ a✝¹ → τ₁✝ }>; apply_rules using ExtStlcTyping All goals completed! 🐙
· neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tya✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ₁✝:Tyh:<{ ~(y →ₚ a✝¹ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ₁✝ }>h₁:¬x = y⊢ <{ Γ ⊢ ~(if x = y then <{ λ ~y : a✝¹ . a✝ }> else <{ λ ~y : a✝¹ . [~x := v] a✝ }>) ⦂ a✝¹ → τ₁✝ }> rw [PartialMap.update_permute neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tya✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ τ₁ ; y →ₚ a✝¹ ; Γ) ⊢ a✝ ⦂ τ₁✝ }>h₁:¬x = y⊢ <{ Γ ⊢ ~(if x = y then <{ λ ~y : a✝¹ . a✝ }> else <{ λ ~y : a✝¹ . [~x := v] a✝ }>) ⦂ a✝¹ → τ₁✝ }>neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tya✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ₁✝:Tyh:<{ ~(y →ₚ a✝¹ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ₁✝ }>h₁:¬x = y⊢ y ≠ x] at h neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tya✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ τ₁ ; y →ₚ a✝¹ ; Γ) ⊢ a✝ ⦂ τ₁✝ }>h₁:¬x = y⊢ <{ Γ ⊢ ~(if x = y then <{ λ ~y : a✝¹ . a✝ }> else <{ λ ~y : a✝¹ . [~x := v] a✝ }>) ⦂ a✝¹ → τ₁✝ }>neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tya✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ₁✝:Tyh:<{ ~(y →ₚ a✝¹ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ₁✝ }>h₁:¬x = y⊢ y ≠ x
· neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tya✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ τ₁ ; y →ₚ a✝¹ ; Γ) ⊢ a✝ ⦂ τ₁✝ }>h₁:¬x = y⊢ <{ Γ ⊢ ~(if x = y then <{ λ ~y : a✝¹ . a✝ }> else <{ λ ~y : a✝¹ . [~x := v] a✝ }>) ⦂ a✝¹ → τ₁✝ }> simp_all neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tya✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ τ₁ ; y →ₚ a✝¹ ; Γ) ⊢ a✝ ⦂ τ₁✝ }>h₁:¬x = y⊢ <{ Γ ⊢ λ ~y : a✝¹ . [~x := v] a✝ ⦂ a✝¹ → τ₁✝ }>; apply_rules using ExtStlcTyping All goals completed! 🐙
· neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tya✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ₁✝:Tyh:<{ ~(y →ₚ a✝¹ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ₁✝ }>h₁:¬x = y⊢ y ≠ x lia All goals completed! 🐙
| sumCase _ y₁ _ y₂ _ ih ih₁ ih₂ => sumCase x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyht:<{ ~(x →ₚ τ₁ ; Γ) ⊢ case a✝² of inl~y₁ => a✝¹ | inr~y₂ => a✝ ⦂ τ }>⊢ <{
Γ ⊢
case [~x := v] a✝² of inl~y₁ => ~(if x = y₁ then a✝¹ else <{ [~x := v] a✝¹ }>) | inr~y₂ =>
~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }>
inversion ht with | _ h₁ h₂ h₃ =>
by_cases x = y₁ pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:x = y₁⊢ <{
Γ ⊢
case [~x := v] a✝² of inl~y₁ => ~(if x = y₁ then a✝¹ else <{ [~x := v] a✝¹ }>) | inr~y₂ =>
~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }>neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:¬x = y₁⊢ <{
Γ ⊢
case [~x := v] a✝² of inl~y₁ => ~(if x = y₁ then a✝¹ else <{ [~x := v] a✝¹ }>) | inr~y₂ =>
~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }> <;> pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:x = y₁⊢ <{
Γ ⊢
case [~x := v] a✝² of inl~y₁ => ~(if x = y₁ then a✝¹ else <{ [~x := v] a✝¹ }>) | inr~y₂ =>
~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }>neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:¬x = y₁⊢ <{
Γ ⊢
case [~x := v] a✝² of inl~y₁ => ~(if x = y₁ then a✝¹ else <{ [~x := v] a✝¹ }>) | inr~y₂ =>
~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }> by_cases x = y₂ pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:x = y₂⊢ <{
Γ ⊢
case [~x := v] a✝² of inl~y₁ => ~(if x = y₁ then a✝¹ else <{ [~x := v] a✝¹ }>) | inr~y₂ =>
~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }>neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{
Γ ⊢
case [~x := v] a✝² of inl~y₁ => ~(if x = y₁ then a✝¹ else <{ [~x := v] a✝¹ }>) | inr~y₂ =>
~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }> <;> pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:x = y₂⊢ <{
Γ ⊢
case [~x := v] a✝² of inl~y₁ => ~(if x = y₁ then a✝¹ else <{ [~x := v] a✝¹ }>) | inr~y₂ =>
~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }>neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:¬x = y₂⊢ <{
Γ ⊢
case [~x := v] a✝² of inl~y₁ => ~(if x = y₁ then a✝¹ else <{ [~x := v] a✝¹ }>) | inr~y₂ =>
~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }>pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:x = y₂⊢ <{
Γ ⊢
case [~x := v] a✝² of inl~y₁ => ~(if x = y₁ then a✝¹ else <{ [~x := v] a✝¹ }>) | inr~y₂ =>
~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }>neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{
Γ ⊢
case [~x := v] a✝² of inl~y₁ => ~(if x = y₁ then a✝¹ else <{ [~x := v] a✝¹ }>) | inr~y₂ =>
~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }> constructor neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{ Γ ⊢ [~x := v] a✝² ⦂ ~?neg.τ₁✝ + ~?neg.τ₂✝ }>neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{ ~(y₁ →ₚ ?neg.τ₁✝ ; Γ) ⊢ ~(if x = y₁ then a✝¹ else <{ [~x := v] a✝¹ }>) ⦂ τ }>neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{ ~(y₂ →ₚ ?neg.τ₂✝ ; Γ) ⊢ ~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>neg.τ₁ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ Tyneg.τ₂ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ Ty <;> pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:x = y₂⊢ <{ Γ ⊢ [~x := v] a✝² ⦂ ~?pos.τ₁✝ + ~?pos.τ₂✝ }>pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:x = y₂⊢ <{ ~(y₁ →ₚ ?pos.τ₁✝ ; Γ) ⊢ ~(if x = y₁ then a✝¹ else <{ [~x := v] a✝¹ }>) ⦂ τ }>pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:x = y₂⊢ <{ ~(y₂ →ₚ ?pos.τ₂✝ ; Γ) ⊢ ~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>pos.τ₁ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:x = y₂⊢ Typos.τ₂ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:x = y₂⊢ Tyneg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:¬x = y₂⊢ <{ Γ ⊢ [~x := v] a✝² ⦂ ~?neg.τ₁✝ + ~?neg.τ₂✝ }>neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:¬x = y₂⊢ <{ ~(y₁ →ₚ ?neg.τ₁✝ ; Γ) ⊢ ~(if x = y₁ then a✝¹ else <{ [~x := v] a✝¹ }>) ⦂ τ }>neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:¬x = y₂⊢ <{ ~(y₂ →ₚ ?neg.τ₂✝ ; Γ) ⊢ ~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>neg.τ₁ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:¬x = y₂⊢ Tyneg.τ₂ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:¬x = y₂⊢ Typos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:x = y₂⊢ <{ Γ ⊢ [~x := v] a✝² ⦂ ~?pos.τ₁✝ + ~?pos.τ₂✝ }>pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:x = y₂⊢ <{ ~(y₁ →ₚ ?pos.τ₁✝ ; Γ) ⊢ ~(if x = y₁ then a✝¹ else <{ [~x := v] a✝¹ }>) ⦂ τ }>pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:x = y₂⊢ <{ ~(y₂ →ₚ ?pos.τ₂✝ ; Γ) ⊢ ~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>pos.τ₁ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:x = y₂⊢ Typos.τ₂ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:x = y₂⊢ Tyneg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{ Γ ⊢ [~x := v] a✝² ⦂ ~?neg.τ₁✝ + ~?neg.τ₂✝ }>neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{ ~(y₁ →ₚ ?neg.τ₁✝ ; Γ) ⊢ ~(if x = y₁ then a✝¹ else <{ [~x := v] a✝¹ }>) ⦂ τ }>neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{ ~(y₂ →ₚ ?neg.τ₂✝ ; Γ) ⊢ ~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>neg.τ₁ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ Tyneg.τ₂ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ Ty first
| apply ih neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{ ~(y₂ →ₚ τ₂✝ ; Γ) ⊢ ~(if x = y₂ then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>; assumption All goals completed! 🐙
| simp_all [PartialMap.update_shadow, PartialMap.update_permute] All goals completed! 🐙
apply ih₁ pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:TmΓ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyih:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝ ⦂ τ }>h₁:<{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬y₂ = y₁h✝:x = y₂⊢ <{ ~(y₂ →ₚ τ₁ ; y₁ →ₚ τ₁✝ ; Γ) ⊢ a✝¹ ⦂ τ }>; rw [PartialMap.update_permute pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:TmΓ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyih:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝ ⦂ τ }>h₁:<{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬y₂ = y₁h✝:x = y₂⊢ <{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:TmΓ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyih:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝ ⦂ τ }>h₁:<{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬y₂ = y₁h✝:x = y₂⊢ y₂ ≠ y₁] pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:TmΓ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyih:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝ ⦂ τ }>h₁:<{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬y₂ = y₁h✝:x = y₂⊢ <{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:TmΓ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyih:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝ ⦂ τ }>h₁:<{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬y₂ = y₁h✝:x = y₂⊢ y₂ ≠ y₁; assumption pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tmy₁:Stringa✝¹:Tmy₂:Stringa✝:TmΓ:Contextτ:Tyτ₁✝:Tyτ₂✝:Tyih:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~y₂ := v] a✝ ⦂ τ }>h₁:<{ ~(y₂ →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ₁✝ + τ₂✝ }>h₂:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₂ →ₚ τ₂✝ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬y₂ = y₁h✝:x = y₂⊢ y₂ ≠ y₁; lia All goals completed! 🐙
| listCase _ _ y₁ y₂ _ ih ih₁ ih₂ => listCase x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyht:<{ ~(x →ₚ τ₁ ; Γ) ⊢ case a✝² of nil => a✝¹ | ~y₁ :: ~y₂ => a✝ ⦂ τ }>⊢ <{
Γ ⊢
case [~x := v] a✝² of nil => [~x := v] a✝¹ | ~y₁ :: ~y₂ =>
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }>
inversion ht with | _ h₁ h₂ h₃ =>
by_cases x = y₁ pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:x = y₁⊢ <{
Γ ⊢
case [~x := v] a✝² of nil => [~x := v] a✝¹ | ~y₁ :: ~y₂ =>
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }>neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:¬x = y₁⊢ <{
Γ ⊢
case [~x := v] a✝² of nil => [~x := v] a✝¹ | ~y₁ :: ~y₂ =>
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }> <;> pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:x = y₁⊢ <{
Γ ⊢
case [~x := v] a✝² of nil => [~x := v] a✝¹ | ~y₁ :: ~y₂ =>
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }>neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:¬x = y₁⊢ <{
Γ ⊢
case [~x := v] a✝² of nil => [~x := v] a✝¹ | ~y₁ :: ~y₂ =>
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }> by_cases x = y₂ pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:x = y₂⊢ <{
Γ ⊢
case [~x := v] a✝² of nil => [~x := v] a✝¹ | ~y₁ :: ~y₂ =>
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }>neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{
Γ ⊢
case [~x := v] a✝² of nil => [~x := v] a✝¹ | ~y₁ :: ~y₂ =>
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }> <;> pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:x = y₂⊢ <{
Γ ⊢
case [~x := v] a✝² of nil => [~x := v] a✝¹ | ~y₁ :: ~y₂ =>
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }>neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:¬x = y₂⊢ <{
Γ ⊢
case [~x := v] a✝² of nil => [~x := v] a✝¹ | ~y₁ :: ~y₂ =>
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }>pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:x = y₂⊢ <{
Γ ⊢
case [~x := v] a✝² of nil => [~x := v] a✝¹ | ~y₁ :: ~y₂ =>
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }>neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{
Γ ⊢
case [~x := v] a✝² of nil => [~x := v] a✝¹ | ~y₁ :: ~y₂ =>
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂
τ }> constructor neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{ Γ ⊢ [~x := v] a✝² ⦂ [ ~?neg.τ₁✝ ] }>neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{
~(y₁ →ₚ ?neg.τ₁✝ ; y₂ →ₚ <{ [ ~?neg.τ₁✝ ] }> ; Γ) ⊢
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>neg.τ₁ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ Ty <;> pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:x = y₂⊢ <{ Γ ⊢ [~x := v] a✝² ⦂ [ ~?pos.τ₁✝ ] }>pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:x = y₂⊢ <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:x = y₂⊢ <{
~(y₁ →ₚ ?pos.τ₁✝ ; y₂ →ₚ <{ [ ~?pos.τ₁✝ ] }> ; Γ) ⊢
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>pos.τ₁ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:x = y₂⊢ Tyneg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:¬x = y₂⊢ <{ Γ ⊢ [~x := v] a✝² ⦂ [ ~?neg.τ₁✝ ] }>neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:¬x = y₂⊢ <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:¬x = y₂⊢ <{
~(y₁ →ₚ ?neg.τ₁✝ ; y₂ →ₚ <{ [ ~?neg.τ₁✝ ] }> ; Γ) ⊢
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>neg.τ₁ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:x = y₁h✝:¬x = y₂⊢ Typos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:x = y₂⊢ <{ Γ ⊢ [~x := v] a✝² ⦂ [ ~?pos.τ₁✝ ] }>pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:x = y₂⊢ <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:x = y₂⊢ <{
~(y₁ →ₚ ?pos.τ₁✝ ; y₂ →ₚ <{ [ ~?pos.τ₁✝ ] }> ; Γ) ⊢
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>pos.τ₁ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:x = y₂⊢ Tyneg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{ Γ ⊢ [~x := v] a✝² ⦂ [ ~?neg.τ₁✝ ] }>neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{
~(y₁ →ₚ ?neg.τ₁✝ ; y₂ →ₚ <{ [ ~?neg.τ₁✝ ] }> ; Γ) ⊢
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>neg.τ₁ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ Ty first
| apply ih neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>a✝²:Tma✝¹:Tmy₁:Stringy₂:Stringa✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝² ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝² ⦂ [ τ₁✝ ] }>h₂:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }>h₃:<{ ~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝¹:¬x = y₁h✝:¬x = y₂⊢ <{
~(y₁ →ₚ τ₁✝ ; y₂ →ₚ <{ [ τ₁✝ ] }> ; Γ) ⊢
~(if (decide (x = y₁) || decide (x = y₂)) = true then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>; assumption All goals completed! 🐙
| simp_all [PartialMap.update_shadow, PartialMap.update_permute] All goals completed! 🐙
| letIn y _ _ ih ih₁ => letIn x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tma✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyht:<{ ~(x →ₚ τ₁ ; Γ) ⊢ let ~y = a✝¹ in a✝ ⦂ τ }>⊢ <{ Γ ⊢ let ~y = [~x := v] a✝¹ in ~(if x = y then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>
inversion ht with | _ h₁ h₂ =>
by_cases x = y pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tma✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ₁✝ }>h₂:<{ ~(y →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:x = y⊢ <{ Γ ⊢ let ~y = [~x := v] a✝¹ in ~(if x = y then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tma✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ₁✝ }>h₂:<{ ~(y →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:¬x = y⊢ <{ Γ ⊢ let ~y = [~x := v] a✝¹ in ~(if x = y then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }> <;> pos x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tma✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ₁✝ }>h₂:<{ ~(y →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:x = y⊢ <{ Γ ⊢ let ~y = [~x := v] a✝¹ in ~(if x = y then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>neg x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tma✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ₁✝ }>h₂:<{ ~(y →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:¬x = y⊢ <{ Γ ⊢ let ~y = [~x := v] a✝¹ in ~(if x = y then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }> constructor neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tma✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ₁✝ }>h₂:<{ ~(y →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:¬x = y⊢ <{ Γ ⊢ [~x := v] a✝¹ ⦂ ~?neg.τ₁✝ }>neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tma✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ₁✝ }>h₂:<{ ~(y →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:¬x = y⊢ <{ ~(y →ₚ ?neg.τ₁✝ ; Γ) ⊢ ~(if x = y then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>neg.τ₁ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tma✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ₁✝ }>h₂:<{ ~(y →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:¬x = y⊢ Ty <;> pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tma✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ₁✝ }>h₂:<{ ~(y →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:x = y⊢ <{ Γ ⊢ [~x := v] a✝¹ ⦂ ~?pos.τ₁✝ }>pos.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tma✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ₁✝ }>h₂:<{ ~(y →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:x = y⊢ <{ ~(y →ₚ ?pos.τ₁✝ ; Γ) ⊢ ~(if x = y then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>pos.τ₁ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tma✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ₁✝ }>h₂:<{ ~(y →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:x = y⊢ Tyneg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tma✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ₁✝ }>h₂:<{ ~(y →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:¬x = y⊢ <{ Γ ⊢ [~x := v] a✝¹ ⦂ ~?neg.τ₁✝ }>neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tma✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ₁✝ }>h₂:<{ ~(y →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:¬x = y⊢ <{ ~(y →ₚ ?neg.τ₁✝ ; Γ) ⊢ ~(if x = y then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>neg.τ₁ x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tma✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ₁✝ }>h₂:<{ ~(y →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:¬x = y⊢ Ty first
| apply ih neg.a x:Stringτ₁:Tyv:Tmhv:<{ ∅ ⊢ v ⦂ τ₁ }>y:Stringa✝¹:Tma✝:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝¹ ⦂ τ }>ih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }> → <{ Γ ⊢ [~x := v] a✝ ⦂ τ }>Γ:Contextτ:Tyτ₁✝:Tyh₁:<{ ~(x →ₚ τ₁ ; Γ) ⊢ a✝¹ ⦂ τ₁✝ }>h₂:<{ ~(y →ₚ τ₁✝ ; x →ₚ τ₁ ; Γ) ⊢ a✝ ⦂ τ }>h✝:¬x = y⊢ <{ ~(y →ₚ τ₁✝ ; Γ) ⊢ ~(if x = y then a✝ else <{ [~x := v] a✝ }>) ⦂ τ }>; assumption All goals completed! 🐙
| simp_all [PartialMap.update_shadow, PartialMap.update_permute] All goals completed! 🐙
Complete the proof of preservation:
theorem preservation (t t' : Tm) (τ : Ty)
(ht : <{ ∅ ⊢ t ⦂ τ }>)
(he : t ⟶ t') :
<{ ∅ ⊢ t' ⦂ τ }> := by t:Tmt':Tmτ:Tyht:<{ ∅ ⊢ t ⦂ τ }>he:t ⟶ t'⊢ <{ ∅ ⊢ t' ⦂ τ }>
generalize heq : (∅ : Context) = Γ at ht t:Tmt':Tmτ:Tyhe:t ⟶ t'Γ:Contextheq:∅ = Γht:<{ Γ ⊢ t ⦂ τ }>⊢ <{ Γ ⊢ t' ⦂ τ }>
induction ht generalizing t' with (subst_vars pair t:Tmτ:TyΓ:Contextt₁✝:Tmt₂✝:Tmτ₁✝:Tyτ₂✝:Tyt':Tmhe:<{ ( t₁✝ , t₂✝ ) }> ⟶ t'a✝¹:<{ ∅ ⊢ t₁✝ ⦂ τ₁✝ }>a✝:<{ ∅ ⊢ t₂✝ ⦂ τ₂✝ }>a_ih✝¹:∀ (t' : Tm), t₁✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁✝ }>a_ih✝:∀ (t' : Tm), t₂✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂✝ }>⊢ <{ ∅ ⊢ t' ⦂ τ₁✝ × τ₂✝ }>; first
-- discharge the goals where `t` doesn't step
| inversion he pair₁ t:Tmτ:TyΓ:Contextt₁✝:Tmt₂✝:Tmτ₁✝:Tyτ₂✝:Tya✝²:<{ ∅ ⊢ t₁✝ ⦂ τ₁✝ }>a✝¹:<{ ∅ ⊢ t₂✝ ⦂ τ₂✝ }>a_ih✝¹:∀ (t' : Tm), t₁✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁✝ }>a_ih✝:∀ (t' : Tm), t₂✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂✝ }>t₁'✝:Tma✝:t₁✝ ⟶ t₁'✝⊢ <{ ∅ ⊢ ( t₁'✝ , t₂✝ ) ⦂ τ₁✝ × τ₂✝ }>pair₂ t:Tmτ:TyΓ:Contextt₁✝:Tmt₂✝:Tmτ₁✝:Tyτ₂✝:Tya✝³:<{ ∅ ⊢ t₁✝ ⦂ τ₁✝ }>a✝²:<{ ∅ ⊢ t₂✝ ⦂ τ₂✝ }>a_ih✝¹:∀ (t' : Tm), t₁✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁✝ }>a_ih✝:∀ (t' : Tm), t₂✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂✝ }>t₂'✝:Tma✝¹:t₁✝.IsValuea✝:t₂✝ ⟶ t₂'✝⊢ <{ ∅ ⊢ ( t₁✝ , t₂'✝ ) ⦂ τ₁✝ × τ₂✝ }> <;> pair₁ t:Tmτ:TyΓ:Contextt₁✝:Tmt₂✝:Tmτ₁✝:Tyτ₂✝:Tya✝²:<{ ∅ ⊢ t₁✝ ⦂ τ₁✝ }>a✝¹:<{ ∅ ⊢ t₂✝ ⦂ τ₂✝ }>a_ih✝¹:∀ (t' : Tm), t₁✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁✝ }>a_ih✝:∀ (t' : Tm), t₂✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂✝ }>t₁'✝:Tma✝:t₁✝ ⟶ t₁'✝⊢ <{ ∅ ⊢ ( t₁'✝ , t₂✝ ) ⦂ τ₁✝ × τ₂✝ }>pair₂ t:Tmτ:TyΓ:Contextt₁✝:Tmt₂✝:Tmτ₁✝:Tyτ₂✝:Tya✝³:<{ ∅ ⊢ t₁✝ ⦂ τ₁✝ }>a✝²:<{ ∅ ⊢ t₂✝ ⦂ τ₂✝ }>a_ih✝¹:∀ (t' : Tm), t₁✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁✝ }>a_ih✝:∀ (t' : Tm), t₂✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂✝ }>t₂'✝:Tma✝¹:t₁✝.IsValuea✝:t₂✝ ⟶ t₂'✝⊢ <{ ∅ ⊢ ( t₁✝ , t₂'✝ ) ⦂ τ₁✝ × τ₂✝ }> constructor pair₂.a t:Tmτ:TyΓ:Contextt₁✝:Tmt₂✝:Tmτ₁✝:Tyτ₂✝:Tya✝³:<{ ∅ ⊢ t₁✝ ⦂ τ₁✝ }>a✝²:<{ ∅ ⊢ t₂✝ ⦂ τ₂✝ }>a_ih✝¹:∀ (t' : Tm), t₁✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁✝ }>a_ih✝:∀ (t' : Tm), t₂✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂✝ }>t₂'✝:Tma✝¹:t₁✝.IsValuea✝:t₂✝ ⟶ t₂'✝⊢ <{ ∅ ⊢ t₁✝ ⦂ τ₁✝ }>pair₂.a t:Tmτ:TyΓ:Contextt₁✝:Tmt₂✝:Tmτ₁✝:Tyτ₂✝:Tya✝³:<{ ∅ ⊢ t₁✝ ⦂ τ₁✝ }>a✝²:<{ ∅ ⊢ t₂✝ ⦂ τ₂✝ }>a_ih✝¹:∀ (t' : Tm), t₁✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁✝ }>a_ih✝:∀ (t' : Tm), t₂✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂✝ }>t₂'✝:Tma✝¹:t₁✝.IsValuea✝:t₂✝ ⟶ t₂'✝⊢ <{ ∅ ⊢ t₂'✝ ⦂ τ₂✝ }> <;> pair₁.a t:Tmτ:TyΓ:Contextt₁✝:Tmt₂✝:Tmτ₁✝:Tyτ₂✝:Tya✝²:<{ ∅ ⊢ t₁✝ ⦂ τ₁✝ }>a✝¹:<{ ∅ ⊢ t₂✝ ⦂ τ₂✝ }>a_ih✝¹:∀ (t' : Tm), t₁✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁✝ }>a_ih✝:∀ (t' : Tm), t₂✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂✝ }>t₁'✝:Tma✝:t₁✝ ⟶ t₁'✝⊢ <{ ∅ ⊢ t₁'✝ ⦂ τ₁✝ }>pair₁.a t:Tmτ:TyΓ:Contextt₁✝:Tmt₂✝:Tmτ₁✝:Tyτ₂✝:Tya✝²:<{ ∅ ⊢ t₁✝ ⦂ τ₁✝ }>a✝¹:<{ ∅ ⊢ t₂✝ ⦂ τ₂✝ }>a_ih✝¹:∀ (t' : Tm), t₁✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁✝ }>a_ih✝:∀ (t' : Tm), t₂✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂✝ }>t₁'✝:Tma✝:t₁✝ ⟶ t₁'✝⊢ <{ ∅ ⊢ t₂✝ ⦂ τ₂✝ }>pair₂.a t:Tmτ:TyΓ:Contextt₁✝:Tmt₂✝:Tmτ₁✝:Tyτ₂✝:Tya✝³:<{ ∅ ⊢ t₁✝ ⦂ τ₁✝ }>a✝²:<{ ∅ ⊢ t₂✝ ⦂ τ₂✝ }>a_ih✝¹:∀ (t' : Tm), t₁✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁✝ }>a_ih✝:∀ (t' : Tm), t₂✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂✝ }>t₂'✝:Tma✝¹:t₁✝.IsValuea✝:t₂✝ ⟶ t₂'✝⊢ <{ ∅ ⊢ t₁✝ ⦂ τ₁✝ }>pair₂.a t:Tmτ:TyΓ:Contextt₁✝:Tmt₂✝:Tmτ₁✝:Tyτ₂✝:Tya✝³:<{ ∅ ⊢ t₁✝ ⦂ τ₁✝ }>a✝²:<{ ∅ ⊢ t₂✝ ⦂ τ₂✝ }>a_ih✝¹:∀ (t' : Tm), t₁✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁✝ }>a_ih✝:∀ (t' : Tm), t₂✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂✝ }>t₂'✝:Tma✝¹:t₁✝.IsValuea✝:t₂✝ ⟶ t₂'✝⊢ <{ ∅ ⊢ t₂'✝ ⦂ τ₂✝ }> simp_all All goals completed! 🐙; done
| try (inversion he fix₁ t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ → τ₁ }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ → τ₁ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ <{ ∅ ⊢ fix t₁'✝ ⦂ τ₁ }>fixAbs t:Tmτ:TyΓ:Contextτ₁:Tyx✝:Stringτ₁✝:Tyt₁✝:Tmh:<{ ∅ ⊢ λ ~x✝ : τ₁✝ . t₁✝ ⦂ τ₁ → τ₁ }>ih:∀ (t' : Tm), <{ λ ~x✝ : τ₁✝ . t₁✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ → τ₁ }>⊢ <{ ∅ ⊢ [~x✝ := fix (λ ~x✝ : τ₁✝ . t₁✝)] t₁✝ ⦂ τ₁ }>; apply_rules using ExtStlcTyping fixAbs t:Tmτ:TyΓ:Contextτ₁:Tyx✝:Stringτ₁✝:Tyt₁✝:Tmh:<{ ∅ ⊢ λ ~x✝ : τ₁✝ . t₁✝ ⦂ τ₁ → τ₁ }>ih:∀ (t' : Tm), <{ λ ~x✝ : τ₁✝ . t₁✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ → τ₁ }>⊢ <{ ∅ ⊢ [~x✝ := fix (λ ~x✝ : τ₁✝ . t₁✝)] t₁✝ ⦂ τ₁ }>; done All goals completed! 🐙))
| app Γ τ₁ τ₂ t₁ t₂ h₁ h₂ ih₁ ih₂ => app t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmt':Tmhe:<{ t₁ t₂ }> ⟶ t'h₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>⊢ <{ ∅ ⊢ t' ⦂ τ₁ }>
inversion he with (try (constructor app₂.h₁ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>t₂'✝:Tma✝¹:t₁.IsValuea✝:t₂ ⟶ t₂'✝⊢ <{ ∅ ⊢ t₁ ⦂ ~?app₂.τ₂ → τ₁ }>app₂.h₂ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>t₂'✝:Tma✝¹:t₁.IsValuea✝:t₂ ⟶ t₂'✝⊢ <{ ∅ ⊢ t₂'✝ ⦂ ~?app₂.τ₂ }>app₂.τ₂ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>t₂'✝:Tma✝¹:t₁.IsValuea✝:t₂ ⟶ t₂'✝⊢ Ty <;> app₂.h₁ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>t₂'✝:Tma✝¹:t₁.IsValuea✝:t₂ ⟶ t₂'✝⊢ <{ ∅ ⊢ t₁ ⦂ ~?app₂.τ₂ → τ₁ }>app₂.h₂ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>t₂'✝:Tma✝¹:t₁.IsValuea✝:t₂ ⟶ t₂'✝⊢ <{ ∅ ⊢ t₂'✝ ⦂ ~?app₂.τ₂ }>app₂.τ₂ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t₁ ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>t₂'✝:Tma✝¹:t₁.IsValuea✝:t₂ ⟶ t₂'✝⊢ Ty apply_rules All goals completed! 🐙; done))
| appAbs _ h =>
apply substitution_preserves_typing (τ₁:=τ₂) appAbs.ht t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>x✝:Stringτ₂✝:Tyt₁✝:Tmh₁:<{ ∅ ⊢ λ ~x✝ : τ₂✝ . t₁✝ ⦂ τ₂ → τ₁ }>ih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂✝ . t₁✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ → τ₁ }>h:t₂.IsValue⊢ <{ ~(x✝ →ₚ τ₂) ⊢ t₁✝ ⦂ τ₁ }>appAbs.hv t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>x✝:Stringτ₂✝:Tyt₁✝:Tmh₁:<{ ∅ ⊢ λ ~x✝ : τ₂✝ . t₁✝ ⦂ τ₂ → τ₁ }>ih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂✝ . t₁✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ → τ₁ }>h:t₂.IsValue⊢ <{ ∅ ⊢ t₂ ⦂ τ₂ }>
· appAbs.ht t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>x✝:Stringτ₂✝:Tyt₁✝:Tmh₁:<{ ∅ ⊢ λ ~x✝ : τ₂✝ . t₁✝ ⦂ τ₂ → τ₁ }>ih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂✝ . t₁✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ → τ₁ }>h:t₂.IsValue⊢ <{ ~(x✝ →ₚ τ₂) ⊢ t₁✝ ⦂ τ₁ }> inversion h₁ abs t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>x✝:Stringt₁✝:Tmh:t₂.IsValueih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂ . t₁✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ → τ₁ }>h✝:<{ ~(x✝ →ₚ τ₂) ⊢ t₁✝ ⦂ τ₁ }>⊢ <{ ~(x✝ →ₚ τ₂) ⊢ t₁✝ ⦂ τ₁ }>; assumption All goals completed! 🐙
· appAbs.hv t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>x✝:Stringτ₂✝:Tyt₁✝:Tmh₁:<{ ∅ ⊢ λ ~x✝ : τ₂✝ . t₁✝ ⦂ τ₂ → τ₁ }>ih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂✝ . t₁✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ → τ₁ }>h:t₂.IsValue⊢ <{ ∅ ⊢ t₂ ⦂ τ₂ }> simp_all All goals completed! 🐙
| ite0 Γ t₁ t₂ t₃ τ h₁ h₂ h₃ ih₁ ih₂ ih₃ => ite0 t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyt':Tmhe:<{ if0 t₁ then t₂ else t₃ }> ⟶ t'h₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>⊢ <{ ∅ ⊢ t' ⦂ τ }>
inversion he if0Step t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>t₁'✝:Tmh✝:t₁ ⟶ t₁'✝⊢ <{ ∅ ⊢ if0 t₁'✝ then t₂ else t₃ ⦂ τ }>if0Zero t:Tmτ✝:TyΓ:Contextt₂:Tmt₃:Tmτ:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>h₁:<{ ∅ ⊢ 0 ⦂ Nat }>ih₁:∀ (t' : Tm), <{ 0 }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ Nat }>⊢ <{ ∅ ⊢ t₂ ⦂ τ }>if0Nonzero t:Tmτ✝:TyΓ:Contextt₂:Tmt₃:Tmτ:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>n✝:Nath₁:<{ ∅ ⊢ ~(Tm.const (n✝ + 1)) ⦂ Nat }>ih₁:∀ (t' : Tm), Tm.const (n✝ + 1) ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ Nat }>⊢ <{ ∅ ⊢ t₃ ⦂ τ }> <;> if0Step t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>t₁'✝:Tmh✝:t₁ ⟶ t₁'✝⊢ <{ ∅ ⊢ if0 t₁'✝ then t₂ else t₃ ⦂ τ }>if0Zero t:Tmτ✝:TyΓ:Contextt₂:Tmt₃:Tmτ:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>h₁:<{ ∅ ⊢ 0 ⦂ Nat }>ih₁:∀ (t' : Tm), <{ 0 }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ Nat }>⊢ <{ ∅ ⊢ t₂ ⦂ τ }>if0Nonzero t:Tmτ✝:TyΓ:Contextt₂:Tmt₃:Tmτ:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>n✝:Nath₁:<{ ∅ ⊢ ~(Tm.const (n✝ + 1)) ⦂ Nat }>ih₁:∀ (t' : Tm), Tm.const (n✝ + 1) ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ Nat }>⊢ <{ ∅ ⊢ t₃ ⦂ τ }> first
| constructor if0Nonzero t:Tmτ✝:TyΓ:Contextt₂:Tmt₃:Tmτ:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>n✝:Nath₁:<{ ∅ ⊢ ~(Tm.const (n✝ + 1)) ⦂ Nat }>ih₁:∀ (t' : Tm), Tm.const (n✝ + 1) ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ Nat }>⊢ <{ ∅ ⊢ t₃ ⦂ τ }> <;> if0Step.h₁ t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>t₁'✝:Tmh✝:t₁ ⟶ t₁'✝⊢ <{ ∅ ⊢ t₁'✝ ⦂ Nat }>if0Step.h₂ t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>t₁'✝:Tmh✝:t₁ ⟶ t₁'✝⊢ <{ ∅ ⊢ t₂ ⦂ τ }>if0Step.h₃ t:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₁:<{ ∅ ⊢ t₁ ⦂ Nat }>h₂:<{ ∅ ⊢ t₂ ⦂ τ }>h₃:<{ ∅ ⊢ t₃ ⦂ τ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ }>t₁'✝:Tmh✝:t₁ ⟶ t₁'✝⊢ <{ ∅ ⊢ t₃ ⦂ τ }> simp_all All goals completed! 🐙
| simp_all All goals completed! 🐙
| sumCase Γ x₁ x₂ τ₁ τ₂ τ₃ t t₁ t₂ h₁ h₂ h₃ ih₁ ih₂ ih₃ => sumCase t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmt':Tmhe:<{ case t of inl~x₁ => t₁ | inr~x₂ => t₂ }> ⟶ t'h₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∀ (t' : Tm), t ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>⊢ <{ ∅ ⊢ t' ⦂ τ₃ }>
inversion he with
| sumCase => constructor sumCase.a t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∀ (t' : Tm), t ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>t'✝:Tma✝:t ⟶ t'✝⊢ <{ ∅ ⊢ t'✝ ⦂ ~?sumCase.τ₁ + ~?sumCase.τ₂ }>sumCase.a t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∀ (t' : Tm), t ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>t'✝:Tma✝:t ⟶ t'✝⊢ <{ ~(x₁ →ₚ ?sumCase.τ₁) ⊢ t₁ ⦂ τ₃ }>sumCase.a t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∀ (t' : Tm), t ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>t'✝:Tma✝:t ⟶ t'✝⊢ <{ ~(x₂ →ₚ ?sumCase.τ₂) ⊢ t₂ ⦂ τ₃ }>sumCase.τ₁ t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∀ (t' : Tm), t ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>t'✝:Tma✝:t ⟶ t'✝⊢ TysumCase.τ₂ t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∀ (t' : Tm), t ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>t'✝:Tma✝:t ⟶ t'✝⊢ Ty <;> sumCase.a t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∀ (t' : Tm), t ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>t'✝:Tma✝:t ⟶ t'✝⊢ <{ ∅ ⊢ t'✝ ⦂ ~?sumCase.τ₁ + ~?sumCase.τ₂ }>sumCase.a t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∀ (t' : Tm), t ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>t'✝:Tma✝:t ⟶ t'✝⊢ <{ ~(x₁ →ₚ ?sumCase.τ₁) ⊢ t₁ ⦂ τ₃ }>sumCase.a t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∀ (t' : Tm), t ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>t'✝:Tma✝:t ⟶ t'✝⊢ <{ ~(x₂ →ₚ ?sumCase.τ₂) ⊢ t₂ ⦂ τ₃ }>sumCase.τ₁ t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∀ (t' : Tm), t ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>t'✝:Tma✝:t ⟶ t'✝⊢ TysumCase.τ₂ t✝:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt:Tmt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ t ⦂ τ₁ + τ₂ }>h₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₁:∀ (t' : Tm), t ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>t'✝:Tma✝:t ⟶ t'✝⊢ Ty apply_rules All goals completed! 🐙
| sumCaseInl =>
apply substitution_preserves_typing (τ₁:=τ₁) sumCaseInl.ht t:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>v✝:Tmτ₂✝:Tya✝:v✝.IsValueh₁:<{ ∅ ⊢ inl τ₂✝ v✝ ⦂ τ₁ + τ₂ }>ih₁:∀ (t' : Tm), <{ inl τ₂✝ v✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>⊢ <{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>sumCaseInl.hv t:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>v✝:Tmτ₂✝:Tya✝:v✝.IsValueh₁:<{ ∅ ⊢ inl τ₂✝ v✝ ⦂ τ₁ + τ₂ }>ih₁:∀ (t' : Tm), <{ inl τ₂✝ v✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>⊢ <{ ∅ ⊢ v✝ ⦂ τ₁ }>
assumption sumCaseInl.hv t:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>v✝:Tmτ₂✝:Tya✝:v✝.IsValueh₁:<{ ∅ ⊢ inl τ₂✝ v✝ ⦂ τ₁ + τ₂ }>ih₁:∀ (t' : Tm), <{ inl τ₂✝ v✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>⊢ <{ ∅ ⊢ v✝ ⦂ τ₁ }>
inversion h₁ sumInl t:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>v✝:Tma✝¹:v✝.IsValuea✝:<{ ∅ ⊢ v✝ ⦂ τ₁ }>ih₁:∀ (t' : Tm), <{ inl τ₂ v✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>⊢ <{ ∅ ⊢ v✝ ⦂ τ₁ }>; trivial All goals completed! 🐙
| sumCaseInr =>
apply substitution_preserves_typing (τ₁:=τ₂) sumCaseInr.ht t:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>v✝:Tmτ₁✝:Tya✝:v✝.IsValueh₁:<{ ∅ ⊢ inr τ₁✝ v✝ ⦂ τ₁ + τ₂ }>ih₁:∀ (t' : Tm), <{ inr τ₁✝ v✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>⊢ <{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>sumCaseInr.hv t:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>v✝:Tmτ₁✝:Tya✝:v✝.IsValueh₁:<{ ∅ ⊢ inr τ₁✝ v✝ ⦂ τ₁ + τ₂ }>ih₁:∀ (t' : Tm), <{ inr τ₁✝ v✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>⊢ <{ ∅ ⊢ v✝ ⦂ τ₂ }>
assumption sumCaseInr.hv t:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>v✝:Tmτ₁✝:Tya✝:v✝.IsValueh₁:<{ ∅ ⊢ inr τ₁✝ v✝ ⦂ τ₁ + τ₂ }>ih₁:∀ (t' : Tm), <{ inr τ₁✝ v✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>⊢ <{ ∅ ⊢ v✝ ⦂ τ₂ }>
inversion h₁ sumInr t:Tmτ:TyΓ:Contextx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyτ₃:Tyt₁:Tmt₂:Tmh₂:<{ ~(x₁ →ₚ τ₁) ⊢ t₁ ⦂ τ₃ }>h₃:<{ ~(x₂ →ₚ τ₂) ⊢ t₂ ⦂ τ₃ }>ih₂:∀ (t' : Tm), t₁ ⟶ t' → ∅ = x₁ →ₚ τ₁ → <{ ~(x₁ →ₚ τ₁) ⊢ t' ⦂ τ₃ }>ih₃:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x₂ →ₚ τ₂ → <{ ~(x₂ →ₚ τ₂) ⊢ t' ⦂ τ₃ }>v✝:Tma✝¹:v✝.IsValueih₁:∀ (t' : Tm), <{ inr τ₁ v✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ + τ₂ }>a✝:<{ ∅ ⊢ v✝ ⦂ τ₂ }>⊢ <{ ∅ ⊢ v✝ ⦂ τ₂ }>; trivial All goals completed! 🐙
| listCase Γ t₁ t₂ t₃ x₁ x₂ τ₁ τ₂ h₁ h₂ h₃ ih₁ ih₂ ih₃ => listCase t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyt':Tmhe:<{ case t₁ of nil => t₂ | ~x₁ :: ~x₂ => t₃ }> ⟶ t'h₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>⊢ <{ ∅ ⊢ t' ⦂ τ₂ }>
inversion he with
| listCase₁ => constructor listCase₁.a t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ <{ ∅ ⊢ t₁'✝ ⦂ [ ~?listCase₁.τ₁ ] }>listCase₁.a t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ <{ ∅ ⊢ t₂ ⦂ τ₂ }>listCase₁.a t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ <{ ~(x₁ →ₚ ?listCase₁.τ₁ ; x₂ →ₚ <{ [ ~?listCase₁.τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>listCase₁.τ₁ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ Ty <;> listCase₁.a t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ <{ ∅ ⊢ t₁'✝ ⦂ [ ~?listCase₁.τ₁ ] }>listCase₁.a t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ <{ ∅ ⊢ t₂ ⦂ τ₂ }>listCase₁.a t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ <{ ~(x₁ →ₚ ?listCase₁.τ₁ ; x₂ →ₚ <{ [ ~?listCase₁.τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>listCase₁.τ₁ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ [ τ₁ ] }>h₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ Ty apply_rules All goals completed! 🐙
| listCaseNil => trivial All goals completed! 🐙
| listCaseCons =>
apply substitution_preserves_typing (τ₁:= <{[ τ₁ ]}>) listCaseCons.ht t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>v₁✝:Tmvl✝:Tma✝¹:v₁✝.IsValuea✝:vl✝.IsValueh₁:<{ ∅ ⊢ v₁✝ :: vl✝ ⦂ [ τ₁ ] }>ih₁:∀ (t' : Tm), <{ v₁✝ :: vl✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>⊢ <{ ~(x₂ →ₚ <{ [ τ₁ ] }>) ⊢ [~x₁ := v₁✝] t₃ ⦂ τ₂ }>listCaseCons.hv t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>v₁✝:Tmvl✝:Tma✝¹:v₁✝.IsValuea✝:vl✝.IsValueh₁:<{ ∅ ⊢ v₁✝ :: vl✝ ⦂ [ τ₁ ] }>ih₁:∀ (t' : Tm), <{ v₁✝ :: vl✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>⊢ <{ ∅ ⊢ vl✝ ⦂ [ τ₁ ] }>
apply substitution_preserves_typing (τ₁:=τ₁) listCaseCons.ht.ht t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>v₁✝:Tmvl✝:Tma✝¹:v₁✝.IsValuea✝:vl✝.IsValueh₁:<{ ∅ ⊢ v₁✝ :: vl✝ ⦂ [ τ₁ ] }>ih₁:∀ (t' : Tm), <{ v₁✝ :: vl✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>⊢ <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>listCaseCons.ht.hv t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>v₁✝:Tmvl✝:Tma✝¹:v₁✝.IsValuea✝:vl✝.IsValueh₁:<{ ∅ ⊢ v₁✝ :: vl✝ ⦂ [ τ₁ ] }>ih₁:∀ (t' : Tm), <{ v₁✝ :: vl✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>⊢ <{ ∅ ⊢ v₁✝ ⦂ τ₁ }>listCaseCons.hv t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>v₁✝:Tmvl✝:Tma✝¹:v₁✝.IsValuea✝:vl✝.IsValueh₁:<{ ∅ ⊢ v₁✝ :: vl✝ ⦂ [ τ₁ ] }>ih₁:∀ (t' : Tm), <{ v₁✝ :: vl✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>⊢ <{ ∅ ⊢ vl✝ ⦂ [ τ₁ ] }>
assumption listCaseCons.ht.hv t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>v₁✝:Tmvl✝:Tma✝¹:v₁✝.IsValuea✝:vl✝.IsValueh₁:<{ ∅ ⊢ v₁✝ :: vl✝ ⦂ [ τ₁ ] }>ih₁:∀ (t' : Tm), <{ v₁✝ :: vl✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>⊢ <{ ∅ ⊢ v₁✝ ⦂ τ₁ }>listCaseCons.hv t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>v₁✝:Tmvl✝:Tma✝¹:v₁✝.IsValuea✝:vl✝.IsValueh₁:<{ ∅ ⊢ v₁✝ :: vl✝ ⦂ [ τ₁ ] }>ih₁:∀ (t' : Tm), <{ v₁✝ :: vl✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>⊢ <{ ∅ ⊢ vl✝ ⦂ [ τ₁ ] }>
inversion h₁ listCons t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>v₁✝:Tmvl✝:Tma✝³:v₁✝.IsValuea✝²:vl✝.IsValueih₁:∀ (t' : Tm), <{ v₁✝ :: vl✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>a✝¹:<{ ∅ ⊢ v₁✝ ⦂ τ₁ }>a✝:<{ ∅ ⊢ vl✝ ⦂ [ τ₁ ] }>⊢ <{ ∅ ⊢ v₁✝ ⦂ τ₁ }>listCaseCons.hv t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>v₁✝:Tmvl✝:Tma✝¹:v₁✝.IsValuea✝:vl✝.IsValueh₁:<{ ∅ ⊢ v₁✝ :: vl✝ ⦂ [ τ₁ ] }>ih₁:∀ (t' : Tm), <{ v₁✝ :: vl✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>⊢ <{ ∅ ⊢ vl✝ ⦂ [ τ₁ ] }>; trivial listCaseCons.hv t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>v₁✝:Tmvl✝:Tma✝¹:v₁✝.IsValuea✝:vl✝.IsValueh₁:<{ ∅ ⊢ v₁✝ :: vl✝ ⦂ [ τ₁ ] }>ih₁:∀ (t' : Tm), <{ v₁✝ :: vl✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>⊢ <{ ∅ ⊢ vl✝ ⦂ [ τ₁ ] }>
inversion h₁ listCons t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmx₁:Stringx₂:Stringτ₁:Tyτ₂:Tyh₂:<{ ∅ ⊢ t₂ ⦂ τ₂ }>h₃:<{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t₃ ⦂ τ₂ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₂ }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }> → <{ ~(x₁ →ₚ τ₁ ; x₂ →ₚ <{ [ τ₁ ] }>) ⊢ t' ⦂ τ₂ }>v₁✝:Tmvl✝:Tma✝³:v₁✝.IsValuea✝²:vl✝.IsValueih₁:∀ (t' : Tm), <{ v₁✝ :: vl✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ [ τ₁ ] }>a✝¹:<{ ∅ ⊢ v₁✝ ⦂ τ₁ }>a✝:<{ ∅ ⊢ vl✝ ⦂ [ τ₁ ] }>⊢ <{ ∅ ⊢ vl✝ ⦂ [ τ₁ ] }>; trivial All goals completed! 🐙
-- Complete the proof...
| fst Γ t τ₁ τ₂ h _ => fst t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyt':Tmhe:<{ fst t }> ⟶ t'h:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>a_ih✝:∀ (t' : Tm), t ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ × τ₂ }>⊢ <{ ∅ ⊢ t' ⦂ τ₁ }>
inversion he fst₁ t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>a_ih✝:∀ (t' : Tm), t ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ × τ₂ }>t'✝:Tma✝:t ⟶ t'✝⊢ <{ ∅ ⊢ fst t'✝ ⦂ τ₁ }>fstPair t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt':Tmv₂✝:Tma✝¹:v₂✝.IsValuea✝:t'.IsValueh:<{ ∅ ⊢ ( t' , v₂✝ ) ⦂ τ₁ × τ₂ }>a_ih✝:∀ (t'_1 : Tm), <{ ( t' , v₂✝ ) }> ⟶ t'_1 → ∅ = ∅ → <{ ∅ ⊢ t'_1 ⦂ τ₁ × τ₂ }>⊢ <{ ∅ ⊢ t' ⦂ τ₁ }>; apply_rules using ExtStlcTyping fstPair t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt':Tmv₂✝:Tma✝¹:v₂✝.IsValuea✝:t'.IsValueh:<{ ∅ ⊢ ( t' , v₂✝ ) ⦂ τ₁ × τ₂ }>a_ih✝:∀ (t'_1 : Tm), <{ ( t' , v₂✝ ) }> ⟶ t'_1 → ∅ = ∅ → <{ ∅ ⊢ t'_1 ⦂ τ₁ × τ₂ }>⊢ <{ ∅ ⊢ t' ⦂ τ₁ }>
inversion h pair t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt':Tmv₂✝:Tma✝³:v₂✝.IsValuea✝²:t'.IsValuea_ih✝:∀ (t'_1 : Tm), <{ ( t' , v₂✝ ) }> ⟶ t'_1 → ∅ = ∅ → <{ ∅ ⊢ t'_1 ⦂ τ₁ × τ₂ }>a✝¹:<{ ∅ ⊢ t' ⦂ τ₁ }>a✝:<{ ∅ ⊢ v₂✝ ⦂ τ₂ }>⊢ <{ ∅ ⊢ t' ⦂ τ₁ }>; assumption All goals completed! 🐙
| snd Γ t τ₁ τ₂ h _ => snd t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyt':Tmhe:<{ snd t }> ⟶ t'h:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>a_ih✝:∀ (t' : Tm), t ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ × τ₂ }>⊢ <{ ∅ ⊢ t' ⦂ τ₂ }>
inversion he snd₁ t✝:Tmτ:TyΓ:Contextt:Tmτ₁:Tyτ₂:Tyh:<{ ∅ ⊢ t ⦂ τ₁ × τ₂ }>a_ih✝:∀ (t' : Tm), t ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ × τ₂ }>t'✝:Tma✝:t ⟶ t'✝⊢ <{ ∅ ⊢ snd t'✝ ⦂ τ₂ }>sndPair t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt':Tmv₁✝:Tma✝¹:v₁✝.IsValuea✝:t'.IsValueh:<{ ∅ ⊢ ( v₁✝ , t' ) ⦂ τ₁ × τ₂ }>a_ih✝:∀ (t'_1 : Tm), <{ ( v₁✝ , t' ) }> ⟶ t'_1 → ∅ = ∅ → <{ ∅ ⊢ t'_1 ⦂ τ₁ × τ₂ }>⊢ <{ ∅ ⊢ t' ⦂ τ₂ }>; apply_rules using ExtStlcTyping sndPair t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt':Tmv₁✝:Tma✝¹:v₁✝.IsValuea✝:t'.IsValueh:<{ ∅ ⊢ ( v₁✝ , t' ) ⦂ τ₁ × τ₂ }>a_ih✝:∀ (t'_1 : Tm), <{ ( v₁✝ , t' ) }> ⟶ t'_1 → ∅ = ∅ → <{ ∅ ⊢ t'_1 ⦂ τ₁ × τ₂ }>⊢ <{ ∅ ⊢ t' ⦂ τ₂ }>
inversion h pair t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt':Tmv₁✝:Tma✝³:v₁✝.IsValuea✝²:t'.IsValuea_ih✝:∀ (t'_1 : Tm), <{ ( v₁✝ , t' ) }> ⟶ t'_1 → ∅ = ∅ → <{ ∅ ⊢ t'_1 ⦂ τ₁ × τ₂ }>a✝¹:<{ ∅ ⊢ v₁✝ ⦂ τ₁ }>a✝:<{ ∅ ⊢ t' ⦂ τ₂ }>⊢ <{ ∅ ⊢ t' ⦂ τ₂ }>; assumption All goals completed! 🐙
| letIn Γ x t₁ t₂ τ₁ τ₂ h₁ h₂ ih₁ ih₂ => letIn t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyt':Tmhe:<{ let ~x = t₁ in t₂ }> ⟶ t'h₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x →ₚ τ₁ → <{ ~(x →ₚ τ₁) ⊢ t' ⦂ τ₂ }>⊢ <{ ∅ ⊢ t' ⦂ τ₂ }>
inversion he with
| let₁ =>
constructor let₁.a t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x →ₚ τ₁ → <{ ~(x →ₚ τ₁) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ <{ ∅ ⊢ t₁'✝ ⦂ ~?let₁.τ₁ }>let₁.a t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x →ₚ τ₁ → <{ ~(x →ₚ τ₁) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ <{ ~(x →ₚ ?let₁.τ₁) ⊢ t₂ ⦂ τ₂ }>let₁.τ₁ t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x →ₚ τ₁ → <{ ~(x →ₚ τ₁) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ Ty
· let₁.a t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x →ₚ τ₁ → <{ ~(x →ₚ τ₁) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ <{ ∅ ⊢ t₁'✝ ⦂ ~?let₁.τ₁ }> apply ih₁ let₁.a.he t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x →ₚ τ₁ → <{ ~(x →ₚ τ₁) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ t₁ ⟶ t₁'✝let₁.a.heq t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x →ₚ τ₁ → <{ ~(x →ₚ τ₁) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ ∅ = ∅ <;> let₁.a.he t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x →ₚ τ₁ → <{ ~(x →ₚ τ₁) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ t₁ ⟶ t₁'✝let₁.a.heq t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x →ₚ τ₁ → <{ ~(x →ₚ τ₁) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ ∅ = ∅ trivial All goals completed! 🐙
· let₁.a t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x →ₚ τ₁ → <{ ~(x →ₚ τ₁) ⊢ t' ⦂ τ₂ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ <{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }> assumption All goals completed! 🐙
| letValue =>
apply substitution_preserves_typing (τ₁:=τ₁) letValue.ht t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x →ₚ τ₁ → <{ ~(x →ₚ τ₁) ⊢ t' ⦂ τ₂ }>a✝:t₁.IsValue⊢ <{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>letValue.hv t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x →ₚ τ₁ → <{ ~(x →ₚ τ₁) ⊢ t' ⦂ τ₂ }>a✝:t₁.IsValue⊢ <{ ∅ ⊢ t₁ ⦂ τ₁ }> <;> letValue.ht t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x →ₚ τ₁ → <{ ~(x →ₚ τ₁) ⊢ t' ⦂ τ₂ }>a✝:t₁.IsValue⊢ <{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>letValue.hv t:Tmτ:TyΓ:Contextx:Stringt₁:Tmt₂:Tmτ₁:Tyτ₂:Tyh₁:<{ ∅ ⊢ t₁ ⦂ τ₁ }>h₂:<{ ~(x →ₚ τ₁) ⊢ t₂ ⦂ τ₂ }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = x →ₚ τ₁ → <{ ~(x →ₚ τ₁) ⊢ t' ⦂ τ₂ }>a✝:t₁.IsValue⊢ <{ ∅ ⊢ t₁ ⦂ τ₁ }> trivial All goals completed! 🐙
| fix Γ t₁ τ₁ h ih => fix t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyt':Tmhe:<{ fix t₁ }> ⟶ t'h:<{ ∅ ⊢ t₁ ⦂ τ₁ → τ₁ }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ → τ₁ }>⊢ <{ ∅ ⊢ t' ⦂ τ₁ }>
inversion he with
| fix₁ =>
constructor fix₁ t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ → τ₁ }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ → τ₁ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ <{ ∅ ⊢ t₁'✝ ⦂ τ₁ → τ₁ }>; apply ih fix₁.he t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ → τ₁ }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ → τ₁ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ t₁ ⟶ t₁'✝fix₁.heq t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ → τ₁ }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ → τ₁ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ ∅ = ∅ <;> fix₁.he t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ → τ₁ }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ → τ₁ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ t₁ ⟶ t₁'✝fix₁.heq t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyh:<{ ∅ ⊢ t₁ ⦂ τ₁ → τ₁ }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ → τ₁ }>t₁'✝:Tma✝:t₁ ⟶ t₁'✝⊢ ∅ = ∅ trivial All goals completed! 🐙
| fixAbs =>
apply substitution_preserves_typing (τ₁:=τ₁) fixAbs.ht t:Tmτ:TyΓ:Contextτ₁:Tyx✝:Stringτ₁✝:Tyt₁✝:Tmh:<{ ∅ ⊢ λ ~x✝ : τ₁✝ . t₁✝ ⦂ τ₁ → τ₁ }>ih:∀ (t' : Tm), <{ λ ~x✝ : τ₁✝ . t₁✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ → τ₁ }>⊢ <{ ~(x✝ →ₚ τ₁) ⊢ t₁✝ ⦂ τ₁ }>fixAbs.hv t:Tmτ:TyΓ:Contextτ₁:Tyx✝:Stringτ₁✝:Tyt₁✝:Tmh:<{ ∅ ⊢ λ ~x✝ : τ₁✝ . t₁✝ ⦂ τ₁ → τ₁ }>ih:∀ (t' : Tm), <{ λ ~x✝ : τ₁✝ . t₁✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ → τ₁ }>⊢ <{ ∅ ⊢ fix (λ ~x✝ : τ₁✝ . t₁✝) ⦂ τ₁ }>
· fixAbs.ht t:Tmτ:TyΓ:Contextτ₁:Tyx✝:Stringτ₁✝:Tyt₁✝:Tmh:<{ ∅ ⊢ λ ~x✝ : τ₁✝ . t₁✝ ⦂ τ₁ → τ₁ }>ih:∀ (t' : Tm), <{ λ ~x✝ : τ₁✝ . t₁✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ → τ₁ }>⊢ <{ ~(x✝ →ₚ τ₁) ⊢ t₁✝ ⦂ τ₁ }> inversion h abs t:Tmτ:TyΓ:Contextτ₁:Tyx✝:Stringt₁✝:Tmih:∀ (t' : Tm), <{ λ ~x✝ : τ₁ . t₁✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ → τ₁ }>h✝:<{ ~(x✝ →ₚ τ₁) ⊢ t₁✝ ⦂ τ₁ }>⊢ <{ ~(x✝ →ₚ τ₁) ⊢ t₁✝ ⦂ τ₁ }>; trivial All goals completed! 🐙
· fixAbs.hv t:Tmτ:TyΓ:Contextτ₁:Tyx✝:Stringτ₁✝:Tyt₁✝:Tmh:<{ ∅ ⊢ λ ~x✝ : τ₁✝ . t₁✝ ⦂ τ₁ → τ₁ }>ih:∀ (t' : Tm), <{ λ ~x✝ : τ₁✝ . t₁✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ → τ₁ }>⊢ <{ ∅ ⊢ fix (λ ~x✝ : τ₁✝ . t₁✝) ⦂ τ₁ }> constructor fixAbs.hv t:Tmτ:TyΓ:Contextτ₁:Tyx✝:Stringτ₁✝:Tyt₁✝:Tmh:<{ ∅ ⊢ λ ~x✝ : τ₁✝ . t₁✝ ⦂ τ₁ → τ₁ }>ih:∀ (t' : Tm), <{ λ ~x✝ : τ₁✝ . t₁✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ t' ⦂ τ₁ → τ₁ }>⊢ <{ ∅ ⊢ λ ~x✝ : τ₁✝ . t₁✝ ⦂ τ₁ → τ₁ }>; trivial All goals completed! 🐙
end StlcExtended