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.
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₂ ⦂ τ₂
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.
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.
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 τ₂.
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.
Quiz
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.
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 OptionNat 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₂
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.
Quiz
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)
Quiz
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
Quiz
What about this one?
case inl Bool 4 of
inl n => n + 3
| inr b => 0
(A) 4 + 3
(B) 7
(C) 0
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 :: x' => case x' of
nil => a
| b :: x'' => 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
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 = λax:Nat.
if x=0 then 1 else x * (fact (pred x)))
we will write:
fact =
fix
(λaf: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 to fact by a fresh variable f.
Add an abstraction binding f at the front, with an
appropriate type annotation. (Since we are using f in place
of fact, which had type Nat→Nat, we should require f
to have the same type.) The new abstraction has type
(Nat→Nat) → (Nat→Nat).
Apply fix to this abstraction. This application has
type Nat→Nat.
Use all of this as the right-hand side of an ordinary
let-binding for fact.
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.)
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".
Quiz
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]
Quiz
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)
Exercise★(halve_fix) (Optional)
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)))
Exercise★(fact_steps) (Optional)
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.
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)}
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₁, ..., in=tn} record
| t.i projection
v ::= Values
| ...
| {i₁=v₁, ..., in=vn} record value
τ ::= Types
| ...
| {i₁:τ₁, ..., in:τn} 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.
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.
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
{τ₁, τ₂, ..., Tn} ⟶ τ₁ * TRest
where {τ₂, ..., τn} ⟶ τn
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:
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.
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₂:τ₂,...ln:τn>
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. ..
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:
namespaceStlcExtendedopenscopedMyGetEleminductiveTy:Typewhere|arrow:Ty→Ty→Ty|nat:Ty|sum:Ty→Ty→Ty|list:Ty→Ty|unit:Ty|prod:Ty→Ty→TyinductiveTm:Typewhere-- 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 ...
Notationsyntax:50stlcTy:51" × "stlcTy:50:stlcTysyntax:50stlcTy:51" + "stlcTy:50:stlcTysyntax:51" [ "stlcTy:50" ] ":stlcTyscopedmacro_rules(kind:=Stlc.tyBracket)|`(<{~$τ:term}>)=>pureτ|`(<{($τ:stlcTy)}>)=>`(<{$τ:stlcTy}>)|`(<{$x:ident}>)=>matchx.getId.toStringwith|"Nat"=>`(Ty.nat)|"Unit"=>`(Ty.unit)|_=>`(($x:Ty))|`(<{[$τ₁:stlcTy]}>)=>`(Ty.list<{$τ₁:stlcTy}>)|`(<{$τ₁:stlcTy→$τ₂:stlcTy}>)=>`(Ty.arrow<{$τ₁:stlcTy}><{$τ₂:stlcTy}>)|`(<{$τ₁:stlcTy×$τ₂:stlcTy}>)=>`(Ty.prod<{$τ₁:stlcTy}><{$τ₂:stlcTy}>)|`(<{$τ₁:stlcTy+$τ₂:stlcTy}>)=>`(Ty.sum<{$τ₁:stlcTy}><{$τ₂:stlcTy}>)|`(<{$τ₁:stlcTy->$τ₂:stlcTy}>)=>`(Ty.arrow<{$τ₁:stlcTy}><{$τ₂:stlcTy}>)Ty.nat.arrowTy.nat : Ty#check<{Nat->Nat}><{ListNat}> : Stlc.Tm#check<{ListNat}>(Ty.nat.prodTy.nat).arrowTy.nat : Ty#check<{(Nat×Nat)->Nat}>(Ty.nat.sumTy.nat).arrowTy.nat : Ty#check<{(Nat+Nat)→Nat}>scopedsyntax:maxnum:stlcTmscopedsyntax:60stlcTm:61" * "stlcTm:60:stlcTmscopedsyntax:50"if0 "stlcTm:51" then "stlcTm:50" else "stlcTm:50:stlcTmscopedsyntax:60" inr "stlcTy:60ppSpacestlcTm:60:stlcTmscopedsyntax:60" inl "stlcTy:60ppSpacestlcTm:60:stlcTmscopedsyntax:50"case "stlcTm:50" of ""inl"stlcVar" => "stlcTm:50" | ""inr"stlcVar" => "stlcTm:50:stlcTmscopedsyntax:60" nil "stlcTy:60:stlcTmscopedsyntax:60stlcTm:61" :: "stlcTm:60:stlcTmscopedsyntax:50"case "stlcTm:50" of ""nil"" => "stlcTm:50" | "stlcVar" :: "stlcVar" => "stlcTm:50:stlcTmscopedsyntax:max" ( "stlcTm:60" , "stlcTm:60" ) ":stlcTmscopedsyntax:50"let "stlcVar" = "stlcTm:50" in "stlcTm:50:stlcTmopenLeaninscopedmacro_rules(kind:=Stlc.tmBracket)|`(<{~$e:term}>)=>puree|`(<{($t:stlcTm)}>)=>`(<{$t:stlcTm}>)|`(<{$x:ident}>)=>matchx.getId.toStringwith|"Nat"=>Macro.throwErrorAtx"`Nat` is a type, not a term"|"Unit"=>Macro.throwErrorAtx"`Unit` is a type, not a term"|"succ"=>Macro.throwErrorAtx"`succ` must be applied to an argument"|"fst"=>Macro.throwErrorAtx"`fst` must be applied to an argument"|"snd"=>Macro.throwErrorAtx"`snd` must be applied to an argument"|"nil"=>Macro.throwErrorAtx"`nil` must be applied to an argument"|"pred"=>Macro.throwErrorAtx"`pred` must be applied to an argument"|"inl"=>Macro.throwErrorAtx"`inl` must be applied to two arguments"|"inr"=>Macro.throwErrorAtx"`inr` must be applied to two arguments"|"fix"=>Macro.throwErrorAtx"`fix` must be applied to an argument"|"unit"=>`(Tm.unit)|_=>`(Tm.var$(quotex.getId.toString))|`(<{λ$x:$τ.$t}>)=>do`(Tm.abs$(←Stlc.varStrx)<{$τ:stlcTy}><{$t:stlcTm}>)|`(<{$t₁:stlcTm$t₂:stlcTm}>)=>matcht₁with|`(stlcTm|$f:ident)=>matchf.getId.toStringwith|"succ"=>`(Tm.succ<{$t₂:stlcTm}>)|"pred"=>`(Tm.pred<{$t₂:stlcTm}>)|"fst"=>`(Tm.fst<{$t₂:stlcTm}>)|"snd"=>`(Tm.snd<{$t₂:stlcTm}>)|"inl"=>Macro.throwErrorAtf"`inl` must be applied to two arguments"|"inr"=>Macro.throwErrorAtf"`inr` must be applied to two arguments"|"fix"=>`(Tm.fix<{$t₂:stlcTm}>)|_=>`(Tm.app<{$t₁:stlcTm}><{$t₂:stlcTm}>)|_=>`(Tm.app<{$t₁:stlcTm}><{$t₂:stlcTm}>)|`(<{$n:num}>)=>`(Tm.const$n)|`(<{$t₁:stlcTm*$t₂:stlcTm}>)=>`(Tm.mult<{$t₁:stlcTm}><{$t₂:stlcTm}>)|`(<{if0$cthen$telse$e}>)=>`(Tm.ite0<{$c:stlcTm}><{$t:stlcTm}><{$e:stlcTm}>)|`(<{inl$τ$t}>)=>`(Tm.sumInl<{$τ:stlcTy}><{$t:stlcTm}>)|`(<{inr$τ$t}>)=>`(Tm.sumInr<{$τ:stlcTy}><{$t:stlcTm}>)|`(<{case$tofinl$x₁=>$t₁|inr$x₂=>$t₂}>)=>do`(Tm.sumCase<{$t:stlcTm}>$(←Stlc.varStrx₁)<{$t₁:stlcTm}>$(←Stlc.varStrx₂)<{$t₂:stlcTm}>)|`(<{nil$τ}>)=>`(Tm.listNil<{$τ:stlcTy}>)|`(<{$t₁:stlcTm::$t₂:stlcTm}>)=>`(Tm.listCons<{$t₁:stlcTm}><{$t₂:stlcTm}>)|`(<{case$tofnil=>$t₁|$x₁::$x₂=>$t₂}>)=>do`(Tm.listCase<{$t:stlcTm}><{$t₁:stlcTm}>$(←Stlc.varStrx₁)$(←Stlc.varStrx₂)<{$t₂:stlcTm}>)|`(<{($t₁:stlcTm,$t₂:stlcTm)}>)=>`(Tm.pair<{$t₁:stlcTm}><{$t₂:stlcTm}>)|`(<{let$x=$t₁in$t₂}>)=>do`(Tm.letIn$(←Stlc.varStrx)<{$t₁:stlcTm}><{$t₂:stlcTm}>)((Tm.var"x").listCons(Tm.var"y")).listCase(Tm.const0)"x""y"(Tm.const1) : Tm#check<{casex::yofnil=>0|x::y=>1}>Tm.sumInlTy.nat((Tm.const3).pair(Tm.const4)) : Tm#check<{inlNat(3,4)}>openLeanin/-- Is `s` usable as a bare variable in `stlcTm` rather than as reserved syntax? -/defisPlainTmVarName(s:String):Bool:=Stlc.isPlainNames&&s!="Nat"&&s!="succ"&&s!="pred"&&s!="unit"&&s!="Unit"&&s!="inl"&&s!="inr"&&s!="if0"&&s!="case"&&s!="nil"&&s!="fix"openLeanPrettyPrinterDelaboratorSubExprin/-- Rebuild `stlcTy` concrete syntax from a `Ty` value. -/partialdefdelabTyInner:DelabM(TSyntax`stlcTy):=doletstx←match_expr←getExprwith|Ty.nat=>`(stlcTy|$(mkIdent`Nat):ident)|Ty.unit=>`(stlcTy|$(mkIdent`Unit):ident)|Ty.arrow__=>doleta←withAppFn<|withAppArgdelabTyInnerletb←withAppArgdelabTyInner`(stlcTy|$a→$b)|Ty.prod__=>doleta←withAppFn<|withAppArgdelabTyInnerletb←withAppArgdelabTyInner`(stlcTy|$a×$b)|Ty.sum__=>doleta←withAppFn<|withAppArgdelabTyInnerletb←withAppArgdelabTyInner`(stlcTy|$a+$b)|Ty.list_=>doletb←withAppArgdelabTyInner`(stlcTy|[$b])|_=>domatch←delabwith|`($i:ident)=>`(stlcTy|$i:ident)|e=>`(stlcTy|~$e)(⟨·⟩)<$>annotateTermInfo⟨stx.raw⟩openLeanPrettyPrinterDelaboratorSubExprin/-- Rebuild `stlcTm` concrete syntax from a `Tm` value. -/partialdefdelabTmInner:DelabM(TSyntax`stlcTm):=doletstx←match_expr←getExprwith|Tm.var_=>doletx←withAppArgdelabmatchxwith|`($s:str)=>ifisPlainTmVarNames.getStringthen`(stlcTm|$(mkIdent(Name.mkSimples.getString)):ident)elseletvar:Term:=mkIdent``Tm.var`(stlcTm|~($var$x))|_=>letvar:Term:=mkIdent``Tm.var`(stlcTm|~($var$x))|Tm.const_=>doletn←withAppArgdelabmatchnwith|`($n:num)=>`(stlcTm|$n:num)|_=>letconst:Term:=mkIdent``Tm.const`(stlcTm|~($const$n))|Tm.app__=>doletf←withAppFn<|withAppArgdelabTmInnerleta←withAppArgdelabTmInner`(stlcTm|$f$a)|Tm.abs___=>doletx←withAppFn<|withAppFn<|withAppArgStlc.delabVarInnerletτ←withAppFn<|withAppArgdelabTyInnerlett←withAppArgdelabTmInner`(stlcTm|λ$x:$τ.$t)|Tm.letIn___=>doletx←withAppFn<|withAppFn<|withAppArgStlc.delabVarInnerlett₁←withAppFn<|withAppArgdelabTmInnerlett₂←withAppArgdelabTmInner`(stlcTm|let$x=$t₁in$t₂)|Tm.succ_=>dolett←withAppArgdelabTmInner`(stlcTm|$(mkIdent`succ):ident$t)|Tm.pred_=>dolett←withAppArgdelabTmInner`(stlcTm|$(mkIdent`pred):ident$t)|Tm.mult__=>doleta←withAppFn<|withAppArgdelabTmInnerletb←withAppArgdelabTmInner`(stlcTm|$a*$b)|Tm.ite0___=>doletc←withAppFn<|withAppFn<|withAppArgdelabTmInnerlett←withAppFn<|withAppArgdelabTmInnerlete←withAppArgdelabTmInner`(stlcTm|if0$cthen$telse$e)|Tm.sumInl__=>doletτ←withAppFn<|withAppArgdelabTyInnerlett←withAppArgdelabTmInner`(stlcTm|inl$τ$t)|Tm.sumInr__=>doletτ←withAppFn<|withAppArgdelabTyInnerlett←withAppArgdelabTmInner`(stlcTm|inr$τ$t)|Tm.sumCase_____=>doletc←withAppFn<|withAppFn<|withAppFn<|withAppFn<|withAppArgdelabTmInnerletx₁←withAppFn<|withAppFn<|withAppFn<|withAppArgStlc.delabVarInnerlett₁←withAppFn<|withAppFn<|withAppArgdelabTmInnerletx₂←withAppFn<|withAppArgStlc.delabVarInnerlett₂←withAppArgdelabTmInner`(stlcTm|case$cofinl$x₁=>$t₁|inr$x₂=>$t₂)|Tm.listNil_=>dolett←withAppArgdelabTyInner`(stlcTm|nil$t)|Tm.listCons__=>doleta←withAppFn<|withAppArgdelabTmInnerletb←withAppArgdelabTmInner`(stlcTm|$a::$b)|Tm.pair__=>doleta←withAppFn<|withAppArgdelabTmInnerletb←withAppArgdelabTmInner`(stlcTm|($a,$b))|Tm.fst_=>doletb←withAppArgdelabTmInner`(stlcTm|$(mkIdent`fst):ident$b)|Tm.snd_=>doletb←withAppArgdelabTmInner`(stlcTm|$(mkIdent`snd):ident$b)|Tm.listCase_____=>doletc←withAppFn<|withAppFn<|withAppFn<|withAppFn<|withAppArgdelabTmInnerlett₁←withAppFn<|withAppFn<|withAppFn<|withAppArgdelabTmInnerletx₁←withAppFn<|withAppFn<|withAppArgStlc.delabVarInnerletx₂←withAppFn<|withAppArgStlc.delabVarInnerlett₂←withAppArgdelabTmInner`(stlcTm|case$cofnil=>$t₁|$x₁::$x₂=>$t₂)|Tm.fix_=>dolett←withAppArgdelabTmInner`(stlcTm|$(mkIdent`fix):ident$t)|Tm.unit=>do`(stlcTm|$(mkIdent`unit):ident)|_=>do-- `subst` is defined below, so it is matched by name rather than with-- `match_expr`; a substitution prints in its own bracket notation.lete←getExprife.getAppFn.constName?==some`SltcExtended.subst&&e.getAppNumArgs==3thenletx←withAppFn<|withAppFn<|withAppArgStlc.delabVarInnerlets←withAppFn<|withAppArgdelabTmInnerlett←withAppArgdelabTmInner`(stlcTm|[$x:=$s]$t)elsematch←delabwith|`($i:ident)=>`(stlcTm|$i:ident)|e=>`(stlcTm|~$e)(⟨·⟩)<$>annotateTermInfo⟨stx.raw⟩openLeanPrettyPrinterDelaboratorSubExprin@[delabapp.StlcExtended.Ty.nat,delabapp.StlcExtended.Ty.arrow,delabapp.StlcExtended.Ty.unit,delabapp.StlcExtended.Ty.prod,delabapp.StlcExtended.Ty.sum,delabapp.StlcExtended.Ty.list]defdelabTy:Delab:=whenPPOptiongetPPNotationdoguard<|match_expr←getExprwith|Ty.nat=>true|Ty.arrow__=>true|Ty.prod__=>true|Ty.sum__=>true|Ty.list_=>true|Ty.unit=>true|_=>falsematch←delabTyInnerwith|`(stlcTy|~$e)=>puree|e=>`(<{$e:stlcTy}>)openLeanPrettyPrinterDelaboratorSubExprin@[delabapp.StlcExtended.Tm.var,delabapp.StlcExtended.Tm.app,delabapp.StlcExtended.Tm.abs,delabapp.StlcExtended.Tm.const,delabapp.StlcExtended.Tm.succ,delabapp.StlcExtended.Tm.pred,delabapp.StlcExtended.Tm.mult,delabapp.StlcExtended.Tm.ite0,delabapp.StlcExtended.Tm.listNil,delabapp.StlcExtended.Tm.listCons,delabapp.StlcExtended.Tm.listCase,delabapp.StlcExtended.Tm.sumInl,delabapp.StlcExtended.Tm.sumInr,delabapp.StlcExtended.Tm.sumCase,delabapp.StlcExtended.Tm.pair,delabapp.StlcExtended.Tm.fst,delabapp.StlcExtended.Tm.snd,delabapp.StlcExtended.Tm.unit,delabapp.StlcExtended.Tm.letIn,delabapp.StlcExtended.Tm.fix]defdelabTm:Delab:=whenPPOptiongetPPNotationdoguard<|match_expr←getExprwith|Tm.var_=>true|Tm.app__=>true|Tm.abs___=>true|Tm.const_=>true|Tm.succ_=>true|Tm.pred_=>true|Tm.mult__=>true|Tm.ite0___=>true|Tm.unit=>true|Tm.fix_=>true|Tm.letIn___=>true|Tm.sumInl__=>true|Tm.sumInr__=>true|Tm.sumCase_____=>true|Tm.listNil_=>true|Tm.listCons__=>true|Tm.listCase_____=>true|Tm.pair__=>true|Tm.fst_=>true|Tm.snd_=>true|_=>falsematch←delabTmInnerwith|`(stlcTm|~($e))=>puree|`(stlcTm|~$e)=>puree|e=>`(<{$e:stlcTm}>)
Checks that the extended grammar parses the way it should.
Exercise★★★(STLCExtended.subst) (Manually graded)
sectionset_optionhygienefalseinlocalmacro_rules(kind:=Stlc.tmBracket)|`(<{[$x:=$s]$t}>)=>do`(subst$(←Stlc.varStrx)<{$s:stlcTm}><{$t:stlcTm}>)defdeclaration uses `sorry`declaration uses `sorry`declaration uses `sorry`subst(x:String)(s:Tm)(t:Tm):Tm:=matchtwith-- pure STLC|.vary=>ifx=ythenselset|<{λ~y:~τ.~t₁}>=>ifx=ythentelse<{λ~y:~τ.[~x:=~s]~t₁}>|<{~t₁~t₂}>=><{([~x:=~s]~t₁)([~x:=~s]~t₂)}>-- numbers|.const_=>t|<{succ~t₁}>=><{succ([~x:=~s]~t₁)}>|<{pred~t₁}>=><{pred([~x:=~s]~t₁)}>|<{~t₁*~t₂}>=><{([~x:=~s]~t₁)*([~x:=~s]~t₂)}>|<{if0~t₁then~t₂else~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₁)}>|<{case~tofinl~x₁=>~t₁|inr~x₂=>~t₂}>=>lett₁:=ifx=x₁thent₁else<{[~x:=~s]~t₁}>lett₂:=ifx=x₂thent₂else<{[~x:=~s]~t₂}><{case([~x:=~s]~t)ofinl~x₁=>~t₁|inr~x₂=>~t₂}>-- lists|.listNil_=>t|<{~t₁::~t₂}>=><{([~x:=~s]~t₁)::[~x:=~s]~t₂}>|<{case~t₁ofnil=>~t₂|~x₁::~x₂=>~t₃}>=>lett₃:=ifx=x₁||x=x₂thent₃else<{[~x:=~s]~t₃}><{case([~x:=~s]~t₁)ofnil=>[~x:=~s]~t₂|~x₁::~x₂=>~t₃}>-- unit|.unit=><{unit}>-- Complete the following cases.-- pairs|<{(~t₁,~t₂)}>=>sorry|Tm.fstt=>sorry|Tm.sndt=>sorry-- let|<{let~y=~t₁in~t₂}>=>sorry-- fix|<{fix~t₁}>=>sorryendmacro_rules(kind:=Stlc.tmBracket)|`(<{[$x:=$s]$t}>)=>do`(subst$(←Stlc.varStrx)<{$s:stlcTm}><{$t:stlcTm}>)
Make sure the following tests are valid by reflexivity:
sectionset_optionhygienefalseinlocalnotation:40t:41" ⟶ "t':41=>Steptt'inductiveStep:Tm→Tm→Propwhere-- 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.constn)}>⟶Tm.const(n+1)|pred(t₁t₁':Tm)(h:t₁⟶t₁'):<{pred~t₁}>⟶<{pred~t₁'}>|predConst(n:Nat):<{pred~(Tm.constn)}>⟶Tm.const(n-1)|multConst(n₁n₂:Nat):<{~(Tm.constn₁)*~(Tm.constn₂)}>⟶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):<{if00then~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(tt':Tm)(x₁:String)(t₁:Tm)(x₂:String)(t₂:Tm):t⟶t'→<{case~tofinl~x₁=>~t₁|inr~x₂=>~t₂}>⟶<{case~t'ofinl~x₁=>~t₁|inr~x₂=>~t₂}>|sumCaseInl(v:Tm)(x₁:String)(t₁:Tm)(x₂:String)(t₂:Tm)(τ₂:Ty):v.IsValue→<{caseinl~τ₂~vofinl~x₁=>~t₁|inr~x₂=>~t₂}>⟶<{[~x₁:=~v]~t₁}>|sumCaseInr(v:Tm)(x₁:String)(t₁:Tm)(x₂:String)(t₂:Tm)(τ₁:Ty):v.IsValue→<{caseinr~τ₁~vofinl~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₁ofnil=>~t₂|~x₁::~x₂=>~t₃}>⟶<{case~t₁'ofnil=>~t₂|~x₁::~x₂=>~t₃}>|listCaseNil(τ₁:Ty)(t₂:Tm)(x₁x₂:String)(t₃:Tm):<{casenil~τ₁ofnil=>~t₂|~x₁::~x₂=>~t₃}>⟶t₂|listCaseCons(v₁vlt₂:Tm)(x₁x₂:String)(t₃:Tm):v₁.IsValue→vl.IsValue→<{case~v₁::~vlofnil=>~t₂|~x₁::~x₂=>~t₃}>⟶<{[~x₂:=~vl]([~x₁:=~v₁]~t₃)}>-- Add rules for the following extensions.-- pairs-- FILL IN HERE-- let-- FILL IN HERE-- fix-- FILL IN HEREendscopednotation:40t:41" ⟶ "t':41=>Steptt'scopednotation:40t:41" ⟶* "t':41=>MultiSteptt'-- Be sure to add your constructors to this list!attribute[ExtStlcEval]Step.appAbsStep.app₁Step.app₂Step.succStep.succNatStep.predStep.predConstStep.multConstStep.mult₁Step.mult₂Step.if0StepStep.if0ZeroStep.if0NonzeroStep.sumInlStep.sumInrStep.sumCaseStep.sumCaseInlStep.sumCaseInrStep.cons₁Step.cons₂Step.listCase₁Step.listCaseNilStep.listCaseCons-- FILL IN HERE
abbrevContext:=PartialMapStringTyNotation encoding: contexts and judgments
The context grammar stlcCtx is reused as well; only the map it denotes is new,
since the types it stores are this language's. As with subst, the judgment
rule is introduced twice: local and hygiene-free while the relation is being
declared, then again for real.
openLeanin/-- The `Context` denoted by a context expression. -/partialdefctxTerm(G:TSyntax`stlcCtx):MacroMTerm:=matchGwith|`(stlcCtx|∅)=>`((∅:Context))|`(stlcCtx|~$e)=>puree|`(stlcCtx|$x:stlcVar↦$τ:stlcTy;$G:stlcCtx)=>do`(PartialMap.update$(←ctxTermG)$(←Stlc.varStrx)<{$τ:stlcTy}>)|_=>Macro.throwUnsupportedsectionStlcExtendedset_optionhygienefalseinlocalmacro_rules(kind:=Stlc.judgeBracket)|`(<{$G:stlcCtx⊢$t:stlcTm⦂$τ:stlcTy}>)=>do`(HasType$(←ctxTermG)<{$t:stlcTm}><{$τ:stlcTy}>)inductiveHasType:Context→Tm→Ty→Propwhere-- pure STLC|var(Γ:Context)(x:String)(τ₁:Ty)(h:Γ[x]=someτ₁):<{~Γ⊢~(Tm.varx)⦂~τ₁}>|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.constn)⦂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)(tt₁t₂:Tm):<{~Γ⊢~t⦂~τ₁+~τ₂}>→<{~x₁↦τ₁;~Γ⊢~t₁⦂~τ₃}>→<{~x₂↦τ₂;~Γ⊢~t₂⦂~τ₃}>→<{~Γ⊢case~tofinl~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₁ofnil=>~t₂|~x₁::~x₂=>~t₃⦂~τ₂}>-- unit|unit(Γ:Context):<{~Γ⊢unit⦂Unit}>-- Add rules for the following extensions.-- pairs-- FILL IN HERE-- let-- FILL IN HERE-- fix-- FILL IN HERE-- Make sure to add your constructors hereattribute[ExtStlcTyping]HasType.varHasType.absHasType.appHasType.constHasType.succHasType.predHasType.multHasType.ite0HasType.sumInlHasType.sumInrHasType.sumCaseHasType.listNilHasType.listConsHasType.listCaseHasType.unit-- FILL IN HERE
Notation encoding: the judgment, for real
Closing the section retires the hygiene-free rule; the same rule is then
declared again, hygienically, for every later use, and a pair of unexpanders
prints judgments back in their own notation.
endStlcExtendedscopedmacro_rules(kind:=Stlc.judgeBracket)|`(<{$G:stlcCtx⊢$t:stlcTm⦂$τ:stlcTy}>)=>do`(HasType$(←ctxTermG)<{$t:stlcTm}><{$τ:stlcTy}>)openLeanPrettyPrinterin/-- Rebuild `stlcCtx` syntax from the term syntax of a `Context`, so that a
context prints as `x ↦ Nat ; Γ` rather than as a chain of map updates. -/partialdefunexpandCtx:Term→UnexpandM(TSyntax`stlcCtx)|`(∅)=>`(stlcCtx|∅)|`($x:str→ₚ$τ)=>dounexpandCtx(←`($x→ₚ$τ;∅))|`($x:str→ₚ$τ;$G)=>doletG'←unexpandCtxGletx':TSyntax`stlcVar←ifStlc.isPlainNamex.getStringthen`(stlcVar|$(mkIdent(Name.mkSimplex.getString)):ident)else`(stlcVar|~$x)matchτwith|`(<{$T':stlcTy}>)=>`(stlcCtx|$x':stlcVar↦$T';$G')|_=>`(stlcCtx|$x':stlcVar↦~($τ);$G')|G=>`(stlcCtx|~($G))openLeanPrettyPrinterin@[app_unexpanderHasType]defHasType.unexpand:Unexpander|`($_$G<{$t:stlcTm}><{$τ:stlcTy}>)=>do`(<{$(←unexpandCtxG)⊢$t⦂$τ}>)|`($_$G<{$t:stlcTm}>$τ)=>do`(<{$(←unexpandCtxG)⊢$t⦂~($τ)}>)|`($_$G$t<{$τ:stlcTy}>)=>do`(<{$(←unexpandCtxG)⊢~($t)⦂$τ}>)|`($_$G$t$τ)=>do`(<{$(←unexpandCtxG)⊢~($t)⦂~($τ)}>)|_=>throw()
Exercise★★★★★(STLCExtended.examples) (Optional)
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.
The proofs of progress and preservation for this enriched system
are essentially the same (though of course longer) as for the pure
STLC.
Exercise★★★(STLCExtended.progress)
Complete the proof of progress
Theorem: Suppose ∅ ⊢ t ⦂ τ. Then either
t is a value, or
t ⟶ t' for some t'.
Proof: By induction on the given typing derivation.
theoremcanonical_forms_fun(t:Tm)(τ₁τ₂:Ty)(ht:<{∅⊢~t⦂~τ₁→~τ₂}>)(hv:t.IsValue):∃xu,t=<{λ~x:~τ₁.~u}>:=t:Tmτ₁:Tyτ₂:Tyht:<{∅⊢~(t)⦂τ₁→τ₂}>hv:t.IsValue⊢ ∃xu,t=<{λ~x:τ₁.u}>inversionhtwith(All goals completed! 🐙)|absxth=>All goals completed! 🐙theoremcanonical_forms_nat(t:Tm)(ht:<{∅⊢~t⦂Nat}>)(hv:t.IsValue):∃n,t=Tm.constn:=t:Tmht:<{∅⊢~(t)⦂Nat}>hv:t.IsValue⊢ ∃n,t=StlcExtended.Tm.constninversionhtwith(All goals completed! 🐙)|natn=>All goals completed! 🐙theoremcanonical_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}>)inversionhtwith(All goals completed! 🐙)|sumInlvhthv=>τ₁: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! 🐙|sumInrvhthv=>τ₁: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! 🐙theoremcanonical_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₂}>inversionhtwith(All goals completed! 🐙)|listNil_=>τ:Ty⊢ <{nilτ}>=<{nilτ}>;All goals completed! 🐙|listConsv₁v₂____=>τ:Tyv₁:Tmv₂:Tma✝³:<{∅⊢~(v₁)⦂~(τ)}>a✝²:<{∅⊢~(v₂)⦂[τ]}>a✝¹:v₁.IsValuea✝:v₂.IsValue⊢ ∃v₁_1v₂_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-- FILL IN HEREtheoremprogress(t:Tm)(τ:Ty)(ht:<{∅⊢~t⦂~τ}>):t.IsValue∨existst',t⟶t':=t:Tmτ:Tyht:<{∅⊢~(t)⦂~(τ)}>⊢ t.IsValue∨∃t',t⟶t't:Tmτ:TyΓ:Contextheq:∅=Γht:<{~(Γ)⊢~(t)⦂~(τ)}>⊢ t.IsValue∨∃t',t⟶t'Alternative `fix` has not been providedAlternative `pair` has not been providedAlternative `fst` has not been providedAlternative `snd` has not been providedAlternative `letIn` has not been providedinductionhtwith(t:Tmτ:TyΓ:Contextt₁✝:Tmτ₁✝:Tya✝:<{∅⊢~(t₁✝)⦂τ₁✝→τ₁✝}>a_ih✝:∅=∅→t₁✝.IsValue∨∃t',t₁✝⟶t'⊢ <{fixt₁✝}>.IsValue∨∃t',<{fixt₁✝}>⟶t';first-- discharge cases where `t` is obviously a value|try(t:Tmτ:TyΓ:Contextt₁✝:Tmτ₁✝:Tya✝:<{∅⊢~(t₁✝)⦂τ₁✝→τ₁✝}>a_ih✝:∅=∅→t₁✝.IsValue∨∃t',t₁✝⟶t'⊢ <{fixt₁✝}>.IsValue;t:Tmτ:TyΓ:Contextt₁✝:Tmτ₁✝:Tya✝:<{∅⊢~(t₁✝)⦂τ₁✝→τ₁✝}>a_ih✝:∅=∅→t₁✝.IsValue∨∃t',t₁✝⟶t'⊢ <{fixt₁✝}>.IsValue;All goals completed! 🐙))t:Tmτ:TyΓ:Contextx✝:Stringτ₁✝:Tyh✝:∅[x✝]=someτ₁✝⊢ (StlcExtended.Tm.varx✝).IsValue∨∃t',StlcExtended.Tm.varx✝⟶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 valuecase_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 valuecase_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→∃xu,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→∃xu,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→∃xu,t₁=<{λ~x:τ₂.u}>x:Stringv:Tmhv:t₁=<{λ~x:τ₂.v}>⊢ <{t₁t₂}>⟶substxt₂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→∃xu,t₁=<{λ~x:τ₂.u}>x:Stringv:Tmhv:t₁=<{λ~x:τ₂.v}>⊢ <{(λ~x:τ₂.v)t₂}>⟶substxt₂vAll goals completed! 🐙-- t₂ is not a valuecase_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 valuecase_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'⊢ <{succt₁}>.IsValue∨∃t',<{succt₁}>⟶t't:Tmτ:TyΓ:Contextt₁:Tmh:<{∅⊢~(t₁)⦂Nat}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'⊢ ∃t',<{succt₁}>⟶t';t:Tmτ:TyΓ:Contextt₁:Tmh:<{∅⊢~(t₁)⦂Nat}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'h✝:t₁.IsValue⊢ ∃t',<{succt₁}>⟶t't:Tmτ:TyΓ:Contextt₁:Tmh:<{∅⊢~(t₁)⦂Nat}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'h✝:∃t',t₁⟶t'⊢ ∃t',<{succt₁}>⟶t'-- t₁ is a valuecase_ht₁t:Tmτ:TyΓ:Contextt₁:Tmh:<{∅⊢~(t₁)⦂Nat}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ht₁:t₁.IsValue⊢ ∃t',<{succt₁}>⟶t't:Tmτ:TyΓ:Contextt₁:Tmih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ht₁:t₁.IsValueh:t₁.IsValue→∃n,t₁=StlcExtended.Tm.constn⊢ ∃t',<{succt₁}>⟶t't:Tmτ:TyΓ:Contextt₁:Tmih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ht₁:t₁.IsValueh✝:t₁.IsValue→∃n,t₁=StlcExtended.Tm.constnn:Nath:t₁=StlcExtended.Tm.constn⊢ ∃t',<{succt₁}>⟶t';t:Tmτ:TyΓ:Contextt₁:Tmih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ht₁:t₁.IsValueh✝:t₁.IsValue→∃n,t₁=StlcExtended.Tm.constnn:Nath:t₁=StlcExtended.Tm.constn⊢ ∃t',<{succ~(StlcExtended.Tm.constn)}>⟶t'exists(Tm.const(n+1))t:Tmτ:TyΓ:Contextt₁:Tmih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ht₁:t₁.IsValueh✝:t₁.IsValue→∃n,t₁=StlcExtended.Tm.constnn:Nath:t₁=StlcExtended.Tm.constn⊢ <{succ~(StlcExtended.Tm.constn)}>⟶StlcExtended.Tm.const(n+1);apply_rulesusingExtStlcEvalAll goals completed! 🐙-- t₁ is not a valuecase_ht₁=>t:Tmτ:TyΓ:Contextt₁:Tmh:<{∅⊢~(t₁)⦂Nat}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ht₁:∃t',t₁⟶t'⊢ ∃t',<{succt₁}>⟶t'obtain⟨t₁',ht₁⟩:=ht₁t:Tmτ:TyΓ:Contextt₁:Tmh:<{∅⊢~(t₁)⦂Nat}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t't₁':Tmht₁:t₁⟶t₁'⊢ ∃t',<{succt₁}>⟶t'exists<{succ~t₁'}>t:Tmτ:TyΓ:Contextt₁:Tmh:<{∅⊢~(t₁)⦂Nat}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t't₁':Tmht₁:t₁⟶t₁'⊢ <{succt₁}>⟶<{succt₁'}>;apply_rulesusingExtStlcEvalAll goals completed! 🐙|predΓt₁hih=>predt:Tmτ:TyΓ:Contextt₁:Tmh:<{∅⊢~(t₁)⦂Nat}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'⊢ <{predt₁}>.IsValue∨∃t',<{predt₁}>⟶t'rightpredt:Tmτ:TyΓ:Contextt₁:Tmh:<{∅⊢~(t₁)⦂Nat}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'⊢ ∃t',<{predt₁}>⟶t';casesihrflpred.inlt:Tmτ:TyΓ:Contextt₁:Tmh:<{∅⊢~(t₁)⦂Nat}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'h✝:t₁.IsValue⊢ ∃t',<{predt₁}>⟶t'pred.inrt:Tmτ:TyΓ:Contextt₁:Tmh:<{∅⊢~(t₁)⦂Nat}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'h✝:∃t',t₁⟶t'⊢ ∃t',<{predt₁}>⟶t'-- t₁ is a valuecase_ht₁=>t:Tmτ:TyΓ:Contextt₁:Tmh:<{∅⊢~(t₁)⦂Nat}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ht₁:t₁.IsValue⊢ ∃t',<{predt₁}>⟶t'applycanonical_forms_natatht:Tmτ:TyΓ:Contextt₁:Tmih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ht₁:t₁.IsValueh:t₁.IsValue→∃n,t₁=StlcExtended.Tm.constn⊢ ∃t',<{predt₁}>⟶t'obtain⟨n,h⟩:=hht₁t:Tmτ:TyΓ:Contextt₁:Tmih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ht₁:t₁.IsValueh✝:t₁.IsValue→∃n,t₁=StlcExtended.Tm.constnn:Nath:t₁=StlcExtended.Tm.constn⊢ ∃t',<{predt₁}>⟶t';rw[ht:Tmτ:TyΓ:Contextt₁:Tmih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ht₁:t₁.IsValueh✝:t₁.IsValue→∃n,t₁=StlcExtended.Tm.constnn:Nath:t₁=StlcExtended.Tm.constn⊢ ∃t',<{pred~(StlcExtended.Tm.constn)}>⟶t']t:Tmτ:TyΓ:Contextt₁:Tmih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ht₁:t₁.IsValueh✝:t₁.IsValue→∃n,t₁=StlcExtended.Tm.constnn:Nath:t₁=StlcExtended.Tm.constn⊢ ∃t',<{pred~(StlcExtended.Tm.constn)}>⟶t'exists(Tm.const(n-1))t:Tmτ:TyΓ:Contextt₁:Tmih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ht₁:t₁.IsValueh✝:t₁.IsValue→∃n,t₁=StlcExtended.Tm.constnn:Nath:t₁=StlcExtended.Tm.constn⊢ <{pred~(StlcExtended.Tm.constn)}>⟶StlcExtended.Tm.const(n-1);apply_rulesusingExtStlcEvalAll goals completed! 🐙case_ht₁=>t:Tmτ:TyΓ:Contextt₁:Tmh:<{∅⊢~(t₁)⦂Nat}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ht₁:∃t',t₁⟶t'⊢ ∃t',<{predt₁}>⟶t'obtain⟨t₁',ht₁⟩:=ht₁t:Tmτ:TyΓ:Contextt₁:Tmh:<{∅⊢~(t₁)⦂Nat}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t't₁':Tmht₁:t₁⟶t₁'⊢ ∃t',<{predt₁}>⟶t'exists<{pred~t₁'}>t:Tmτ:TyΓ:Contextt₁:Tmh:<{∅⊢~(t₁)⦂Nat}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t't₁':Tmht₁:t₁⟶t₁'⊢ <{predt₁}>⟶<{predt₁'}>;apply_rulesusingExtStlcEvalAll goals completed! 🐙|multΓt₁t₂h₁h₂ih₁ih₂=>multt: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'rightmultt: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';casesih₁rflmult.inlt: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.inrt: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 valuecase_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'casesih₂rflinlt: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'inrt: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 valuecase_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'applycanonical_forms_natath₁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₁=StlcExtended.Tm.constn⊢ ∃t',<{t₁*t₂}>⟶t'applycanonical_forms_natath₂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₁=StlcExtended.Tm.constnh₂:t₂.IsValue→∃n,t₂=StlcExtended.Tm.constn⊢ ∃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₁=StlcExtended.Tm.constnh₂:t₂.IsValue→∃n,t₂=StlcExtended.Tm.constnn₁:Nath₁:t₁=StlcExtended.Tm.constn₁⊢ ∃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₁=StlcExtended.Tm.constnh₂✝:t₂.IsValue→∃n,t₂=StlcExtended.Tm.constnn₁:Nath₁:t₁=StlcExtended.Tm.constn₁n₂:Nath₂:t₂=StlcExtended.Tm.constn₂⊢ ∃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₁=StlcExtended.Tm.constnh₂✝:t₂.IsValue→∃n,t₂=StlcExtended.Tm.constnn₁:Nath₁:t₁=StlcExtended.Tm.constn₁n₂:Nath₂:t₂=StlcExtended.Tm.constn₂⊢ <{t₁*t₂}>⟶StlcExtended.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₁=StlcExtended.Tm.constnh₂✝:t₂.IsValue→∃n,t₂=StlcExtended.Tm.constnn₁:Nath₁:t₁=StlcExtended.Tm.constn₁n₂:Nath₂:t₂=StlcExtended.Tm.constn₂⊢ <{~(StlcExtended.Tm.constn₁)*~(StlcExtended.Tm.constn₂)}>⟶StlcExtended.Tm.const(n₁*n₂)apply_rulesusingExtStlcEvalAll goals completed! 🐙-- t₂ is not a valuecase_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_rulesusingExtStlcEvalAll goals completed! 🐙-- t₁ is not a valuecase_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_rulesusingExtStlcEvalAll goals completed! 🐙|ite0Γt₁t₂t₃τh₁h₂h₃ih₁ih₂ih₃=>ite0t: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'⊢ <{if0t₁thent₂elset₃}>.IsValue∨∃t',<{if0t₁thent₂elset₃}>⟶t'rightite0t: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',<{if0t₁thent₂elset₃}>⟶t';casesih₁rflite0.inlt: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',<{if0t₁thent₂elset₃}>⟶t'ite0.inrt: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',<{if0t₁thent₂elset₃}>⟶t'-- t₁ is a valuecase_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',<{if0t₁thent₂elset₃}>⟶t'applycanonical_forms_natath₁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₁=StlcExtended.Tm.constn⊢ ∃t',<{if0t₁thent₂elset₃}>⟶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₁=StlcExtended.Tm.constnn₁:Nath₁:t₁=StlcExtended.Tm.constn₁⊢ ∃t',<{if0t₁thent₂elset₃}>⟶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₁=StlcExtended.Tm.constnn₁:Nath₁:t₁=StlcExtended.Tm.constn₁⊢ ∃t',<{if0~(StlcExtended.Tm.constn₁)thent₂elset₃}>⟶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₁=StlcExtended.Tm.constnn₁:Nath₁:t₁=StlcExtended.Tm.constn₁⊢ ∃t',<{if0~(StlcExtended.Tm.constn₁)thent₂elset₃}>⟶t';casesn₁zerot: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₁=StlcExtended.Tm.constnh₁:t₁=<{0}>⊢ ∃t',<{if00thent₂elset₃}>⟶t'succt: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₁=StlcExtended.Tm.constnn✝:Nath₁:t₁=StlcExtended.Tm.const(n✝+1)⊢ ∃t',<{if0~(StlcExtended.Tm.const(n✝+1))thent₂elset₃}>⟶t'·zerot: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₁=StlcExtended.Tm.constnh₁:t₁=<{0}>⊢ ∃t',<{if00thent₂elset₃}>⟶t'existst₂zerot: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₁=StlcExtended.Tm.constnh₁:t₁=<{0}>⊢ <{if00thent₂elset₃}>⟶t₂;apply_rulesusingExtStlcEvalAll goals completed! 🐙·succt: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₁=StlcExtended.Tm.constnn✝:Nath₁:t₁=StlcExtended.Tm.const(n✝+1)⊢ ∃t',<{if0~(StlcExtended.Tm.const(n✝+1))thent₂elset₃}>⟶t'existst₃succt: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₁=StlcExtended.Tm.constnn✝:Nath₁:t₁=StlcExtended.Tm.const(n✝+1)⊢ <{if0~(StlcExtended.Tm.const(n✝+1))thent₂elset₃}>⟶t₃;apply_rulesusingExtStlcEvalAll goals completed! 🐙-- t₁ is not a valuecase_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',<{if0t₁thent₂elset₃}>⟶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',<{if0t₁thent₂elset₃}>⟶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₁'⊢ <{if0t₁thent₂elset₃}>⟶<{if0t₁'thent₂elset₃}>;apply_rulesusingExtStlcEvalAll goals completed! 🐙|sumInlΓt₁τ₁τ₂hih=>sumInlt:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyh:<{∅⊢~(t₁)⦂~(τ₁)}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'⊢ <{inlτ₂t₁}>.IsValue∨∃t',<{inlτ₂t₁}>⟶t'casesihrflsumInl.inlt:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyh:<{∅⊢~(t₁)⦂~(τ₁)}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'h✝:t₁.IsValue⊢ <{inlτ₂t₁}>.IsValue∨∃t',<{inlτ₂t₁}>⟶t'sumInl.inrt: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 valuecase_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'leftt:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyh:<{∅⊢~(t₁)⦂~(τ₁)}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ht₁:t₁.IsValue⊢ <{inlτ₂t₁}>.IsValue;apply_rulesusingExtStlcEvalAll goals completed! 🐙-- t₁ is not a valuecase_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'rightt: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_rulesusingExtStlcEvalAll goals completed! 🐙|sumInrΓt₂τ₁τ₂hih=>sumInrt:Tmτ:TyΓ:Contextt₂:Tmτ₁:Tyτ₂:Tyh:<{∅⊢~(t₂)⦂~(τ₂)}>ih:∅=∅→t₂.IsValue∨∃t',t₂⟶t'⊢ <{inrτ₁t₂}>.IsValue∨∃t',<{inrτ₁t₂}>⟶t'casesihrflsumInr.inlt:Tmτ:TyΓ:Contextt₂:Tmτ₁:Tyτ₂:Tyh:<{∅⊢~(t₂)⦂~(τ₂)}>ih:∅=∅→t₂.IsValue∨∃t',t₂⟶t'h✝:t₂.IsValue⊢ <{inrτ₁t₂}>.IsValue∨∃t',<{inrτ₁t₂}>⟶t'sumInr.inrt: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 valuecase_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'leftt:Tmτ:TyΓ:Contextt₂:Tmτ₁:Tyτ₂:Tyh:<{∅⊢~(t₂)⦂~(τ₂)}>ih:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ht₁:t₂.IsValue⊢ <{inrτ₁t₂}>.IsValue;apply_rulesusingExtStlcEvalAll goals completed! 🐙-- t₁ is not a valuecase_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'rightt: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_rulesusingExtStlcEvalAll goals completed! 🐙|sumCaseΓx₁x₂τ₁τ₂τ₃tt₁t₂h₁h₂h₃ih₁ih₂ih₃=>sumCaset✝: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'⊢ <{casetofinl~x₁=>t₁|inr~x₂=>t₂}>.IsValue∨∃t',<{casetofinl~x₁=>t₁|inr~x₂=>t₂}>⟶t'rightsumCaset✝: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',<{casetofinl~x₁=>t₁|inr~x₂=>t₂}>⟶t';casesih₁rflsumCase.inlt✝: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',<{casetofinl~x₁=>t₁|inr~x₂=>t₂}>⟶t'sumCase.inrt✝: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',<{casetofinl~x₁=>t₁|inr~x₂=>t₂}>⟶t'-- t₁ is a valuecase_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',<{casetofinl~x₁=>t₁|inr~x₂=>t₂}>⟶t'applycanonical_forms_sumath₁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',<{casetofinl~x₁=>t₁|inr~x₂=>t₂}>⟶t'obtain⟨v,hv,hl|hr⟩:=h₁htinlt✝: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',<{casetofinl~x₁=>t₁|inr~x₂=>t₂}>⟶t'inrt✝: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',<{casetofinl~x₁=>t₁|inr~x₂=>t₂}>⟶t'·inlt✝: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',<{casetofinl~x₁=>t₁|inr~x₂=>t₂}>⟶t'rw[hlinlt✝: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',<{caseinlτ₂vofinl~x₁=>t₁|inr~x₂=>t₂}>⟶t']inlt✝: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',<{caseinlτ₂vofinl~x₁=>t₁|inr~x₂=>t₂}>⟶t';exists<{[~x₁:=~v]~t₁}>inlt✝: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}>⊢ <{caseinlτ₂vofinl~x₁=>t₁|inr~x₂=>t₂}>⟶substx₁vt₁;apply_rulesusingExtStlcEvalAll goals completed! 🐙·inrt✝: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',<{casetofinl~x₁=>t₁|inr~x₂=>t₂}>⟶t'rw[hrinrt✝: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',<{caseinrτ₁vofinl~x₁=>t₁|inr~x₂=>t₂}>⟶t']inrt✝: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',<{caseinrτ₁vofinl~x₁=>t₁|inr~x₂=>t₂}>⟶t';exists<{[~x₂:=~v]~t₂}>inrt✝: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}>⊢ <{caseinrτ₁vofinl~x₁=>t₁|inr~x₂=>t₂}>⟶substx₂vt₂;apply_rulesusingExtStlcEvalAll goals completed! 🐙-- t₁ is not a valuecase_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',<{casetofinl~x₁=>t₁|inr~x₂=>t₂}>⟶t'obtain⟨t',ht⟩:=htt✝: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',<{casetofinl~x₁=>t₁|inr~x₂=>t₂}>⟶t'exists<{case~t'ofinl~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'⊢ <{casetofinl~x₁=>t₁|inr~x₂=>t₂}>⟶<{caset'ofinl~x₁=>t₁|inr~x₂=>t₂}>;apply_rulesusingExtStlcEvalAll goals completed! 🐙|listConsΓt₁t₂τ₁h₁h₂ih₁ih₂=>listConst: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'casesih₁rfllistCons.inlt: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.inrt: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 valuecase_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'casesih₂rflinlt: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'inrt: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 valuecase_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'leftt: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_rulesusingExtStlcEvalAll goals completed! 🐙-- t₂ is not a valuecase_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'rightt: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_rulesusingExtStlcEvalAll goals completed! 🐙-- t₁ is not a valuecase_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'rightt: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_rulesusingExtStlcEvalAll goals completed! 🐙|listCaseΓt₁t₂t₃x₁x₂τ₁τ₂h₁h₂h₃ih₁ih₂ih₃=>listCaset: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'⊢ <{caset₁ofnil=>t₂|~x₁::~x₂=>t₃}>.IsValue∨∃t',<{caset₁ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t'rightlistCaset: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',<{caset₁ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t';casesih₁rfllistCase.inlt: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',<{caset₁ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t'listCase.inrt: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',<{caset₁ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t'-- t₁ is a valuecase_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',<{caset₁ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t'applycanonical_forms_listath₁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',<{caset₁ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t'obtainhnil|⟨v₁,v₂,hv₁,hv₂,h⟩:=h₁htinlt: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',<{caset₁ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t'inrt: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',<{caset₁ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t'·inlt: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',<{caset₁ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t'rw[hnilinlt: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',<{casenilτ₁ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t']inlt: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',<{casenilτ₁ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t';existst₂inlt: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τ₁}>⊢ <{casenilτ₁ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t₂;apply_rulesusingExtStlcEvalAll goals completed! 🐙·inrt: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',<{caset₁ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t'rw[hinrt: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',<{casev₁::v₂ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t']inrt: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',<{casev₁::v₂ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t';exists<{[~x₂:=~v₂][~x₁:=~v₁]~t₃}>inrt: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₂}>⊢ <{casev₁::v₂ofnil=>t₂|~x₁::~x₂=>t₃}>⟶substx₂v₂(substx₁v₁t₃);apply_rulesusingExtStlcEvalAll goals completed! 🐙-- t₁ is not a valuecase_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',<{caset₁ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t'obtain⟨t',ht⟩:=htt: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',<{caset₁ofnil=>t₂|~x₁::~x₂=>t₃}>⟶t'exists<{case~t'ofnil=>~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'⊢ <{caset₁ofnil=>t₂|~x₁::~x₂=>t₃}>⟶<{caset'ofnil=>t₂|~x₁::~x₂=>t₃}>;apply_rulesusingExtStlcEvalAll goals completed! 🐙-- complete the proof-- FILL IN HERE
Through the power of automation, the weakening proof is exactly the same as for the original STLC.