6. StlcProp: Properties of STLC
In Wadler's "PLF in Agda", he defines an "animator" for STLC terms using the proof terms for progress + preservation. This would be a FANTASTIC example (or, perhaps better, exercise!) for this chapter.
In this chapter, we develop the fundamental theory of the Simply Typed Lambda Calculus — in particular, the type safety theorem.
We pick up where the Stlc chapter left off, so everything below lives in the same namespace as the definitions it is about.
namespace Stlc
open scoped MyGetElem
6.1. Canonical Forms
As we saw for the very simple language in the Types
chapter, the first step in establishing basic properties of
reduction and types is to identify the possible canonical
forms (i.e., well-typed values) belonging to each type. For
Bool, these are again the boolean values true and false; for
arrow types, they are lambda-abstractions.
Formally, we will need these lemmas only for terms that are not only well typed but closed — i.e., well typed in the empty context.
theorem canonical_forms_bool (t : Tm) (hτ : <{ ∅ ⊢ ~t ⦂ Bool }>) (hv : t.IsValue) :
t = <{ true }> ∨ t = <{ false }> := t:Tmhτ:<{ ∅ ⊢ ~(t) ⦂ Bool }>hv:t.IsValue⊢ t = <{ true }> ∨ t = <{ false }>
cases hv with
x:Stringτ:Tyt₁:Tmhτ:<{ ∅ ⊢ λ ~x : τ . t₁ ⦂ Bool }>⊢ <{ λ ~x : τ . t₁ }> = <{ true }> ∨ <{ λ ~x : τ . t₁ }> = <{ false }> All goals completed! 🐙
hτ:<{ ∅ ⊢ true ⦂ Bool }>⊢ <{ true }> = <{ true }> ∨ <{ true }> = <{ false }> hτ:<{ ∅ ⊢ true ⦂ Bool }>⊢ <{ true }> = <{ true }>; All goals completed! 🐙
hτ:<{ ∅ ⊢ false ⦂ Bool }>⊢ <{ false }> = <{ true }> ∨ <{ false }> = <{ false }> hτ:<{ ∅ ⊢ false ⦂ Bool }>⊢ <{ false }> = <{ false }>; All goals completed! 🐙
theorem canonical_forms_fun (t : Tm) (τ₁ τ₂ : Ty)
(hτ : <{ ∅ ⊢ ~t ⦂ ~τ₁ → ~τ₂ }>) (hv : t.IsValue) :
∃ x u, t = <{ λ ~x : ~τ₁ . ~u }> := t:Tmτ₁:Tyτ₂:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ τ₁ → τ₂ }>hv:t.IsValue⊢ ∃ x u, t = <{ λ ~x : τ₁ . u }>
cases hv with
τ₁:Tyτ₂:Tyx:Stringτ:Tyt₁:Tmhτ:<{ ∅ ⊢ λ ~x : τ . t₁ ⦂ τ₁ → τ₂ }>⊢ ∃ x_1 u, <{ λ ~x : τ . t₁ }> = <{ λ ~x_1 : τ₁ . u }> cases hτ with τ₁:Tyτ₂:Tyx:Stringt₁:Tmh✝:<{ ~(x →ₚ τ₁) ⊢ ~(t₁) ⦂ ~(τ₂) }>⊢ ∃ x_1 u, <{ λ ~x : τ₁ . t₁ }> = <{ λ ~x_1 : τ₁ . u }>
All goals completed! 🐙
τ₁:Tyτ₂:Tyhτ:<{ ∅ ⊢ true ⦂ τ₁ → τ₂ }>⊢ ∃ x u, <{ true }> = <{ λ ~x : τ₁ . u }> All goals completed! 🐙
τ₁:Tyτ₂:Tyhτ:<{ ∅ ⊢ false ⦂ τ₁ → τ₂ }>⊢ ∃ x u, <{ false }> = <{ λ ~x : τ₁ . u }> All goals completed! 🐙
6.2. Progress
The progress theorem tells us that closed, well-typed terms are not stuck: either a well-typed term is a value, or it can take a reduction step. The proof is a relatively straightforward extension of the progress proof we saw in the Types chapter. We give the proof in English first, then the formal version.
Proof: By induction on the derivation of ∅ ⊢ t ⦂ τ.
-
The last rule of the derivation cannot be
HasType.var, since a variable is never well typed in an empty context. -
The
HasType.tru,HasType.fls, andHasType.abscases are trivial, since in each of these cases we can see by inspecting the rule thattis a value. -
If the last rule of the derivation is
HasType.app, thenthas the formt₁ t₂for somet₁andt₂, where∅ ⊢ t₁ ⦂ τ₂ → τand∅ ⊢ t₂ ⦂ τ₂for some typeτ₂. The induction hypothesis for the first subderivation says that eithert₁is a value or else it can take a reduction step.-
If
t₁is a value, then considert₂, which by the induction hypothesis for the second subderivation must also either be a value or take a step.-
Suppose
t₂is a value. Sincet₁is a value with an arrow type, it must be a lambda abstraction; hencet₁ t₂can take a step byStep.appAbs. -
Otherwise,
t₂can take a step, and hence so cant₁ t₂byStep.app2.
-
-
If
t₁can take a step, then so cant₁ t₂byStep.app1.
-
-
If the last rule of the derivation is
HasType.ite, thent = if t₁ then t₂ else t₃, wheret₁has typeBool. The first IH says thatt₁either is a value or takes a step.-
If
t₁is a value, then since it has typeBoolit must be eithertrueorfalse. If it istrue, thentsteps tot₂; otherwise it steps tot₃. -
Otherwise,
t₁takes a step, and therefore so doest(byStep.ifStep).
-
theorem progress (t : Tm) (τ : Ty) (hτ : <{ ∅ ⊢ ~t ⦂ ~τ }>) :
t.IsValue ∨ ∃ t', t ⟶ t' := t:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ t.IsValue ∨ ∃ t', t ⟶ t'
t:Tmτ:TyΓ:ContexthΓ:∅ = Γhτ:<{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>⊢ t.IsValue ∨ ∃ t', t ⟶ t'
induction hτ with
t:Tmτ:TyΓ✝:ContextΓ:Contextx:Stringτ₁:Tyh:Γ[x] = some τ₁hΓ:∅ = Γ⊢ (Stlc.Tm.var x).IsValue ∨ ∃ t', Stlc.Tm.var x ⟶ t'
t:Tmτ:TyΓ:Contextx:Stringτ₁:Tyh:∅[x] = some τ₁⊢ (Stlc.Tm.var x).IsValue ∨ ∃ t', Stlc.Tm.var x ⟶ t'
-- Contradictory: variables cannot be typed in an empty context.
var t:Tmτ:TyΓ:Contextx:Stringτ₁:Tyh:none = some τ₁⊢ (Stlc.Tm.var x).IsValue ∨ ∃ t', Stlc.Tm.var x ⟶ t'
cases h All goals completed! 🐙
| abs => abs t:Tmτ:TyΓ:ContextΓ✝:Contextx✝:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>h_ih✝:∅ = x✝ →ₚ T₂✝ ; Γ✝ → t₁✝.IsValue ∨ ∃ t', t₁✝ ⟶ t'hΓ:∅ = Γ✝⊢ <{ λ ~x✝ : T₂✝ . t₁✝ }>.IsValue ∨ ∃ t', <{ λ ~x✝ : T₂✝ . t₁✝ }> ⟶ t' left abs t:Tmτ:TyΓ:ContextΓ✝:Contextx✝:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>h_ih✝:∅ = x✝ →ₚ T₂✝ ; Γ✝ → t₁✝.IsValue ∨ ∃ t', t₁✝ ⟶ t'hΓ:∅ = Γ✝⊢ <{ λ ~x✝ : T₂✝ . t₁✝ }>.IsValue; constructor All goals completed! 🐙
| tru => tru t:Tmτ:TyΓ:ContextΓ✝:ContexthΓ:∅ = Γ✝⊢ <{ true }>.IsValue ∨ ∃ t', <{ true }> ⟶ t' left tru t:Tmτ:TyΓ:ContextΓ✝:ContexthΓ:∅ = Γ✝⊢ <{ true }>.IsValue; constructor All goals completed! 🐙
| fls => fls t:Tmτ:TyΓ:ContextΓ✝:ContexthΓ:∅ = Γ✝⊢ <{ false }>.IsValue ∨ ∃ t', <{ false }> ⟶ t' left fls t:Tmτ:TyΓ:ContextΓ✝:ContexthΓ:∅ = Γ✝⊢ <{ false }>.IsValue; constructor All goals completed! 🐙
| app Γ τ₁ τ₂ t₁ t₂ h₁ h₂ ih₁ ih₂ => app t:Tmτ:TyΓ✝:ContextΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ~(Γ) ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ~(Γ) ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = Γ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = Γ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hΓ:∅ = Γ⊢ <{ t₁ t₂ }>.IsValue ∨ ∃ t', <{ t₁ t₂ }> ⟶ t'
-- `t = t₁ t₂`. Proceed by cases on whether `t₁` is a value or steps.
subst hΓ app 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'
right app 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'
cases ih₁ rfl with
| inl hv₁ => app.inl t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValue⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
cases ih₂ rfl with
| inl hv₂ => app.inl.inl t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuehv₂:t₂.IsValue⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
obtain ⟨x, u, rfl⟩ := canonical_forms_fun t₁ _ _ h₁ hv₁ app.inl.inl t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₂:t₂.IsValuex:Stringu:Tmh₁:<{ ∅ ⊢ λ ~x : τ₂ . u ⦂ τ₂ → τ₁ }>ih₁:∅ = ∅ → <{ λ ~x : τ₂ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . u }> ⟶ t'hv₁:<{ λ ~x : τ₂ . u }>.IsValue⊢ ∃ t', <{ (λ ~x : τ₂ . u) t₂ }> ⟶ t'
exists <{ [~x := ~t₂] ~u }> app.inl.inl t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₂:t₂.IsValuex:Stringu:Tmh₁:<{ ∅ ⊢ λ ~x : τ₂ . u ⦂ τ₂ → τ₁ }>ih₁:∅ = ∅ → <{ λ ~x : τ₂ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . u }> ⟶ t'hv₁:<{ λ ~x : τ₂ . u }>.IsValue⊢ <{ (λ ~x : τ₂ . u) t₂ }> ⟶ <{ [~x := t₂] u }>
constructor app.inl.inl t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₂:t₂.IsValuex:Stringu:Tmh₁:<{ ∅ ⊢ λ ~x : τ₂ . u ⦂ τ₂ → τ₁ }>ih₁:∅ = ∅ → <{ λ ~x : τ₂ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . u }> ⟶ t'hv₁:<{ λ ~x : τ₂ . u }>.IsValue⊢ t₂.IsValue
assumption All goals completed! 🐙
| inr hs₂ => app.inl.inr t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuehs₂:∃ t', t₂ ⟶ t'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
obtain ⟨t₂', h⟩ := hs₂ app.inl.inr t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
exists <{ ~t₁ ~t₂' }> app.inl.inr t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ <{ t₁ t₂ }> ⟶ <{ t₁ t₂' }>
constructor app.inl.inr.hv t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ t₁.IsValueapp.inl.inr.h t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ t₂ ⟶ t₂' <;> app.inl.inr.hv t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ t₁.IsValueapp.inl.inr.h t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ t₂ ⟶ t₂' assumption All goals completed! 🐙
| inr hs₁ => app.inr t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hs₁:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
obtain ⟨t₁', h⟩ := hs₁ app.inr t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
exists <{ ~t₁' ~t₂ }> app.inr t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ <{ t₁ t₂ }> ⟶ <{ t₁' t₂ }>
constructor app.inr t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁' <;> app.inr t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁' assumption All goals completed! 🐙
| ite Γ t₁ t₂ t₃ τ₁ h₁ h₂ h₃ ih₁ ih₂ ih₃ => ite t:Tmτ:TyΓ✝:ContextΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ~(Γ) ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ~(Γ) ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ~(Γ) ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∅ = Γ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = Γ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = Γ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'hΓ:∅ = Γ⊢ <{ if t₁ then t₂ else t₃ }>.IsValue ∨ ∃ t', <{ if t₁ then t₂ else t₃ }> ⟶ t'
subst hΓ ite t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'⊢ <{ if t₁ then t₂ else t₃ }>.IsValue ∨ ∃ t', <{ if t₁ then t₂ else t₃ }> ⟶ t'
right ite t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'⊢ ∃ t', <{ if t₁ then t₂ else t₃ }> ⟶ t'
cases ih₁ rfl with
| inl hv₁ => ite.inl t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'hv₁:t₁.IsValue⊢ ∃ t', <{ if t₁ then t₂ else t₃ }> ⟶ t'
cases canonical_forms_bool t₁ h₁ hv₁ with
| inl he => ite.inl.inl t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'hv₁:t₁.IsValuehe:t₁ = <{ true }>⊢ ∃ t', <{ if t₁ then t₂ else t₃ }> ⟶ t'
subst he ite.inl.inl t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmτ₁:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'h₁:<{ ∅ ⊢ true ⦂ Bool }>ih₁:∅ = ∅ → <{ true }>.IsValue ∨ ∃ t', <{ true }> ⟶ t'hv₁:<{ true }>.IsValue⊢ ∃ t', <{ if true then t₂ else t₃ }> ⟶ t'
exists t₂ ite.inl.inl t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmτ₁:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'h₁:<{ ∅ ⊢ true ⦂ Bool }>ih₁:∅ = ∅ → <{ true }>.IsValue ∨ ∃ t', <{ true }> ⟶ t'hv₁:<{ true }>.IsValue⊢ <{ if true then t₂ else t₃ }> ⟶ t₂
constructor All goals completed! 🐙
| inr he => ite.inl.inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'hv₁:t₁.IsValuehe:t₁ = <{ false }>⊢ ∃ t', <{ if t₁ then t₂ else t₃ }> ⟶ t'
subst he ite.inl.inr t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmτ₁:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'h₁:<{ ∅ ⊢ false ⦂ Bool }>ih₁:∅ = ∅ → <{ false }>.IsValue ∨ ∃ t', <{ false }> ⟶ t'hv₁:<{ false }>.IsValue⊢ ∃ t', <{ if false then t₂ else t₃ }> ⟶ t'
exists t₃ ite.inl.inr t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmτ₁:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'h₁:<{ ∅ ⊢ false ⦂ Bool }>ih₁:∅ = ∅ → <{ false }>.IsValue ∨ ∃ t', <{ false }> ⟶ t'hv₁:<{ false }>.IsValue⊢ <{ if false then t₂ else t₃ }> ⟶ t₃
constructor All goals completed! 🐙
| inr hs₁ => ite.inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'hs₁:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ if t₁ then t₂ else t₃ }> ⟶ t'
obtain ⟨t₁', h⟩ := hs₁ ite.inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ ∃ t', <{ if t₁ then t₂ else t₃ }> ⟶ t'
exists <{ if ~t₁' then ~t₂ else ~t₃ }> ite.inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ <{ if t₁ then t₂ else t₃ }> ⟶ <{ if t₁' then t₂ else t₃ }>
constructor ite.inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'
assumption All goals completed! 🐙
Show that progress can also be proved by induction on terms instead of induction on typing derivations.
theorem progress' (t : Tm) (τ : Ty) (hτ : <{ ∅ ⊢ ~t ⦂ ~τ }>) :
t.IsValue ∨ ∃ t', t ⟶ t' := by t:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ t.IsValue ∨ ∃ t', t ⟶ t'
solution!
induction t generalizing τ with
| var x => var x:Stringτ:Tyhτ:<{ ∅ ⊢ ~(Stlc.Tm.var x) ⦂ ~(τ) }>⊢ (Stlc.Tm.var x).IsValue ∨ ∃ t', Stlc.Tm.var x ⟶ t'
cases hτ with
| var _ _ _ h => var.var x:Stringτ:Tyh:∅[x] = some τ⊢ (Stlc.Tm.var x).IsValue ∨ ∃ t', Stlc.Tm.var x ⟶ t' rw [PartialMap.getElem_empty var.var x:Stringτ:Tyh:none = some τ⊢ (Stlc.Tm.var x).IsValue ∨ ∃ t', Stlc.Tm.var x ⟶ t'] at h var.var x:Stringτ:Tyh:none = some τ⊢ (Stlc.Tm.var x).IsValue ∨ ∃ t', Stlc.Tm.var x ⟶ t'; cases h All goals completed! 🐙
| abs x τ₂ t₁ _ => abs x:Stringτ₂:Tyt₁:Tmt_ih✝:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'τ:Tyhτ:<{ ∅ ⊢ λ ~x : τ₂ . t₁ ⦂ ~(τ) }>⊢ <{ λ ~x : τ₂ . t₁ }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . t₁ }> ⟶ t'
left abs x:Stringτ₂:Tyt₁:Tmt_ih✝:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'τ:Tyhτ:<{ ∅ ⊢ λ ~x : τ₂ . t₁ ⦂ ~(τ) }>⊢ <{ λ ~x : τ₂ . t₁ }>.IsValue
constructor All goals completed! 🐙
| tru => tru τ:Tyhτ:<{ ∅ ⊢ true ⦂ ~(τ) }>⊢ <{ true }>.IsValue ∨ ∃ t', <{ true }> ⟶ t'
left tru τ:Tyhτ:<{ ∅ ⊢ true ⦂ ~(τ) }>⊢ <{ true }>.IsValue
constructor All goals completed! 🐙
| fls => fls τ:Tyhτ:<{ ∅ ⊢ false ⦂ ~(τ) }>⊢ <{ false }>.IsValue ∨ ∃ t', <{ false }> ⟶ t'
left fls τ:Tyhτ:<{ ∅ ⊢ false ⦂ ~(τ) }>⊢ <{ false }>.IsValue
constructor All goals completed! 🐙
| app t₁ t₂ ih₁ ih₂ => app t₁:Tmt₂:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyhτ:<{ ∅ ⊢ t₁ t₂ ⦂ ~(τ) }>⊢ <{ t₁ t₂ }>.IsValue ∨ ∃ t', <{ t₁ t₂ }> ⟶ t'
right app t₁:Tmt₂:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyhτ:<{ ∅ ⊢ t₁ t₂ ⦂ ~(τ) }>⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
cases hτ with
| app _ _ τ₂ _ _ h₁ h₂ => app.app t₁:Tmt₂:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>h₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ }>⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
cases ih₁ _ h₁ with
| inl hv₁ => app.app.inl t₁:Tmt₂:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>h₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ }>hv₁:t₁.IsValue⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
obtain ⟨x, u, rfl⟩ := canonical_forms_fun t₁ _ _ h₁ hv₁ app.app.inl t₂:Tmih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>x:Stringu:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ λ ~x : τ₂ . u ⦂ ~(τ) }> → <{ λ ~x : τ₂ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . u }> ⟶ t'h₁:<{ ∅ ⊢ λ ~x : τ₂ . u ⦂ τ₂ → τ }>hv₁:<{ λ ~x : τ₂ . u }>.IsValue⊢ ∃ t', <{ (λ ~x : τ₂ . u) t₂ }> ⟶ t'
cases ih₂ _ h₂ with
| inl hv₂ => app.app.inl.inl t₂:Tmih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>x:Stringu:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ λ ~x : τ₂ . u ⦂ ~(τ) }> → <{ λ ~x : τ₂ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . u }> ⟶ t'h₁:<{ ∅ ⊢ λ ~x : τ₂ . u ⦂ τ₂ → τ }>hv₁:<{ λ ~x : τ₂ . u }>.IsValuehv₂:t₂.IsValue⊢ ∃ t', <{ (λ ~x : τ₂ . u) t₂ }> ⟶ t'
exists <{ [~x := ~t₂] ~u }> app.app.inl.inl t₂:Tmih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>x:Stringu:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ λ ~x : τ₂ . u ⦂ ~(τ) }> → <{ λ ~x : τ₂ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . u }> ⟶ t'h₁:<{ ∅ ⊢ λ ~x : τ₂ . u ⦂ τ₂ → τ }>hv₁:<{ λ ~x : τ₂ . u }>.IsValuehv₂:t₂.IsValue⊢ <{ (λ ~x : τ₂ . u) t₂ }> ⟶ <{ [~x := t₂] u }>
constructor app.app.inl.inl t₂:Tmih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>x:Stringu:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ λ ~x : τ₂ . u ⦂ ~(τ) }> → <{ λ ~x : τ₂ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . u }> ⟶ t'h₁:<{ ∅ ⊢ λ ~x : τ₂ . u ⦂ τ₂ → τ }>hv₁:<{ λ ~x : τ₂ . u }>.IsValuehv₂:t₂.IsValue⊢ t₂.IsValue <;> app.app.inl.inl t₂:Tmih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>x:Stringu:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ λ ~x : τ₂ . u ⦂ ~(τ) }> → <{ λ ~x : τ₂ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . u }> ⟶ t'h₁:<{ ∅ ⊢ λ ~x : τ₂ . u ⦂ τ₂ → τ }>hv₁:<{ λ ~x : τ₂ . u }>.IsValuehv₂:t₂.IsValue⊢ t₂.IsValue assumption All goals completed! 🐙
| inr hs₂ => app.app.inl.inr t₂:Tmih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>x:Stringu:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ λ ~x : τ₂ . u ⦂ ~(τ) }> → <{ λ ~x : τ₂ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . u }> ⟶ t'h₁:<{ ∅ ⊢ λ ~x : τ₂ . u ⦂ τ₂ → τ }>hv₁:<{ λ ~x : τ₂ . u }>.IsValuehs₂:∃ t', t₂ ⟶ t'⊢ ∃ t', <{ (λ ~x : τ₂ . u) t₂ }> ⟶ t'
obtain ⟨t₂', h⟩ := hs₂ app.app.inl.inr t₂:Tmih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>x:Stringu:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ λ ~x : τ₂ . u ⦂ ~(τ) }> → <{ λ ~x : τ₂ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . u }> ⟶ t'h₁:<{ ∅ ⊢ λ ~x : τ₂ . u ⦂ τ₂ → τ }>hv₁:<{ λ ~x : τ₂ . u }>.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ ∃ t', <{ (λ ~x : τ₂ . u) t₂ }> ⟶ t'
exists <{ (λ ~x : ~τ₂ . ~u) ~t₂' }> app.app.inl.inr t₂:Tmih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>x:Stringu:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ λ ~x : τ₂ . u ⦂ ~(τ) }> → <{ λ ~x : τ₂ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . u }> ⟶ t'h₁:<{ ∅ ⊢ λ ~x : τ₂ . u ⦂ τ₂ → τ }>hv₁:<{ λ ~x : τ₂ . u }>.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ <{ (λ ~x : τ₂ . u) t₂ }> ⟶ <{ (λ ~x : τ₂ . u) t₂' }>
apply Step.app2 app.app.inl.inr.hv t₂:Tmih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>x:Stringu:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ λ ~x : τ₂ . u ⦂ ~(τ) }> → <{ λ ~x : τ₂ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . u }> ⟶ t'h₁:<{ ∅ ⊢ λ ~x : τ₂ . u ⦂ τ₂ → τ }>hv₁:<{ λ ~x : τ₂ . u }>.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ <{ λ ~x : τ₂ . u }>.IsValueapp.app.inl.inr.h t₂:Tmih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>x:Stringu:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ λ ~x : τ₂ . u ⦂ ~(τ) }> → <{ λ ~x : τ₂ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . u }> ⟶ t'h₁:<{ ∅ ⊢ λ ~x : τ₂ . u ⦂ τ₂ → τ }>hv₁:<{ λ ~x : τ₂ . u }>.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ t₂ ⟶ t₂' <;> app.app.inl.inr.hv t₂:Tmih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>x:Stringu:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ λ ~x : τ₂ . u ⦂ ~(τ) }> → <{ λ ~x : τ₂ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . u }> ⟶ t'h₁:<{ ∅ ⊢ λ ~x : τ₂ . u ⦂ τ₂ → τ }>hv₁:<{ λ ~x : τ₂ . u }>.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ <{ λ ~x : τ₂ . u }>.IsValueapp.app.inl.inr.h t₂:Tmih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>x:Stringu:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ λ ~x : τ₂ . u ⦂ ~(τ) }> → <{ λ ~x : τ₂ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . u }> ⟶ t'h₁:<{ ∅ ⊢ λ ~x : τ₂ . u ⦂ τ₂ → τ }>hv₁:<{ λ ~x : τ₂ . u }>.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ t₂ ⟶ t₂' assumption All goals completed! 🐙
| inr hs₁ => app.app.inr t₁:Tmt₂:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>h₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ }>hs₁:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
obtain ⟨t₁', h⟩ := hs₁ app.app.inr t₁:Tmt₂:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>h₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ }>t₁':Tmh:t₁ ⟶ t₁'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
exists <{ ~t₁' ~t₂ }> app.app.inr t₁:Tmt₂:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>h₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ }>t₁':Tmh:t₁ ⟶ t₁'⊢ <{ t₁ t₂ }> ⟶ <{ t₁' t₂ }>
apply Step.app1 app.app.inr t₁:Tmt₂:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'τ:Tyτ₂:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>h₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ }>t₁':Tmh:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'
assumption All goals completed! 🐙
| ite t₁ t₂ t₃ ih₁ ih₂ ih₃ => ite t₁:Tmt₂:Tmt₃:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∀ (τ : Ty), <{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'τ:Tyhτ:<{ ∅ ⊢ if t₁ then t₂ else t₃ ⦂ ~(τ) }>⊢ <{ if t₁ then t₂ else t₃ }>.IsValue ∨ ∃ t', <{ if t₁ then t₂ else t₃ }> ⟶ t'
right ite t₁:Tmt₂:Tmt₃:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∀ (τ : Ty), <{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'τ:Tyhτ:<{ ∅ ⊢ if t₁ then t₂ else t₃ ⦂ ~(τ) }>⊢ ∃ t', <{ if t₁ then t₂ else t₃ }> ⟶ t'
cases hτ with
| ite _ _ _ _ _ h₁ h₂ h₃ => ite.ite t₁:Tmt₂:Tmt₃:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∀ (τ : Ty), <{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'τ:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }>⊢ ∃ t', <{ if t₁ then t₂ else t₃ }> ⟶ t'
cases ih₁ _ h₁ with
| inl hv₁ => ite.ite.inl t₁:Tmt₂:Tmt₃:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∀ (τ : Ty), <{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'τ:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }>hv₁:t₁.IsValue⊢ ∃ t', <{ if t₁ then t₂ else t₃ }> ⟶ t'
cases canonical_forms_bool t₁ h₁ hv₁ with
| inl he => ite.ite.inl.inl t₁:Tmt₂:Tmt₃:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∀ (τ : Ty), <{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'τ:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }>hv₁:t₁.IsValuehe:t₁ = <{ true }>⊢ ∃ t', <{ if t₁ then t₂ else t₃ }> ⟶ t'
subst he ite.ite.inl.inl t₂:Tmt₃:Tmih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∀ (τ : Ty), <{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'τ:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }>ih₁:∀ (τ : Ty), <{ ∅ ⊢ true ⦂ ~(τ) }> → <{ true }>.IsValue ∨ ∃ t', <{ true }> ⟶ t'h₁:<{ ∅ ⊢ true ⦂ Bool }>hv₁:<{ true }>.IsValue⊢ ∃ t', <{ if true then t₂ else t₃ }> ⟶ t'
exists t₂ ite.ite.inl.inl t₂:Tmt₃:Tmih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∀ (τ : Ty), <{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'τ:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }>ih₁:∀ (τ : Ty), <{ ∅ ⊢ true ⦂ ~(τ) }> → <{ true }>.IsValue ∨ ∃ t', <{ true }> ⟶ t'h₁:<{ ∅ ⊢ true ⦂ Bool }>hv₁:<{ true }>.IsValue⊢ <{ if true then t₂ else t₃ }> ⟶ t₂
apply Step.ifTrue All goals completed! 🐙
| inr he => ite.ite.inl.inr t₁:Tmt₂:Tmt₃:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∀ (τ : Ty), <{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'τ:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }>hv₁:t₁.IsValuehe:t₁ = <{ false }>⊢ ∃ t', <{ if t₁ then t₂ else t₃ }> ⟶ t'
subst he ite.ite.inl.inr t₂:Tmt₃:Tmih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∀ (τ : Ty), <{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'τ:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }>ih₁:∀ (τ : Ty), <{ ∅ ⊢ false ⦂ ~(τ) }> → <{ false }>.IsValue ∨ ∃ t', <{ false }> ⟶ t'h₁:<{ ∅ ⊢ false ⦂ Bool }>hv₁:<{ false }>.IsValue⊢ ∃ t', <{ if false then t₂ else t₃ }> ⟶ t'
exists t₃ ite.ite.inl.inr t₂:Tmt₃:Tmih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∀ (τ : Ty), <{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'τ:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }>ih₁:∀ (τ : Ty), <{ ∅ ⊢ false ⦂ ~(τ) }> → <{ false }>.IsValue ∨ ∃ t', <{ false }> ⟶ t'h₁:<{ ∅ ⊢ false ⦂ Bool }>hv₁:<{ false }>.IsValue⊢ <{ if false then t₂ else t₃ }> ⟶ t₃
apply Step.ifFalse All goals completed! 🐙
| inr hs₁ => ite.ite.inr t₁:Tmt₂:Tmt₃:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∀ (τ : Ty), <{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'τ:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }>hs₁:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ if t₁ then t₂ else t₃ }> ⟶ t'
obtain ⟨t₁', h⟩ := hs₁ ite.ite.inr t₁:Tmt₂:Tmt₃:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∀ (τ : Ty), <{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'τ:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }>t₁':Tmh:t₁ ⟶ t₁'⊢ ∃ t', <{ if t₁ then t₂ else t₃ }> ⟶ t'
exists <{ if ~t₁' then ~t₂ else ~t₃ }> ite.ite.inr t₁:Tmt₂:Tmt₃:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∀ (τ : Ty), <{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'τ:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }>t₁':Tmh:t₁ ⟶ t₁'⊢ <{ if t₁ then t₂ else t₃ }> ⟶ <{ if t₁' then t₂ else t₃ }>
apply Step.ifStep ite.ite.inr t₁:Tmt₂:Tmt₃:Tmih₁:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∀ (τ : Ty), <{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }> → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∀ (τ : Ty), <{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }> → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'τ:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ) }>t₁':Tmh:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'
assumption All goals completed! 🐙
6.3. Preservation
The other half of the type soundness property is the preservation of types during reduction. For this part, we'll need to develop some technical machinery for reasoning about variables and substitution. Working from top to bottom (from the high-level property we are actually interested in to the lowest-level technical lemmas that are needed by various cases of the more interesting proofs), the story goes like this:
-
The preservation theorem is proved by induction on a typing derivation and case analysis on the step relation, pretty much as we did in the Types chapter. The one case that is significantly different is the one for the
Step.appAbsrule, whose definition uses the substitution operation. To see that this step preserves typing, we need to know that the substitution itself does. So we prove a... -
substitution lemma, stating that substituting a (closed, well-typed) term
sfor a variablexin a termtpreserves the type oft. The proof goes by induction on the form oftand requires looking at all the different cases in the definition of substitution. This time, for the variables case, we discover that we need to deduce from the fact that a termshas typeσin the empty context the fact thatshas typeσin every context. For this we prove a... -
weakening lemma, showing that typing is preserved under "extensions" to the context
Γ.
To make Lean happy, though, we need to formalize the story in the opposite order, starting with weakening...
6.3.1. The Weakening Lemma
First, we show that typing is preserved under "extensions" to the
context Γ. (Recall map inclusion, Γ ⊆ Γ', from the Typeclasses chapter.)
theorem weakening {Γ Γ' : Context} {t : Tm} {τ : Ty}
(hi : Γ ⊆ Γ') (ht : <{ ~Γ ⊢ ~t ⦂ ~τ }>) : <{ ~Γ' ⊢ ~t ⦂ ~τ }> := by Γ:ContextΓ':Contextt:Tmτ:Tyhi:Γ ⊆ Γ'ht:<{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ~(Γ') ⊢ ~(t) ⦂ ~(τ) }>
induction ht generalizing Γ' with
| var _ x _ h => var Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:Tyh:Γ✝[x] = some T₁✝Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(Stlc.Tm.var x) ⦂ ~(T₁✝) }>
constructor var Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:Tyh:Γ✝[x] = some T₁✝Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ'[x] = some T₁✝
exact hi h All goals completed! 🐙
| abs _ x _ _ _ _ ih => abs Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ {Γ' : Context}, x →ₚ T₂✝ ; Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ λ ~x : T₂✝ . t₁✝ ⦂ T₂✝ → T₁✝ }>
constructor abs Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ {Γ' : Context}, x →ₚ T₂✝ ; Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(x →ₚ T₂✝ ; Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>
apply ih abs Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ {Γ' : Context}, x →ₚ T₂✝ ; Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ x →ₚ T₂✝ ; Γ✝ ⊆ x →ₚ T₂✝ ; Γ'
apply PartialMap.update_subset abs Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ {Γ' : Context}, x →ₚ T₂✝ ; Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ'
assumption All goals completed! 🐙
| app _ _ _ _ _ _ _ ih₁ ih₂ => app Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ t₁✝ t₂✝ ⦂ ~(T₁✝) }>
constructor app.h₁ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~?app.T₂ → T₁✝ }>app.h₂ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(?app.T₂) }>app.T₂ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Ty
· app.h₁ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~?app.T₂ → T₁✝ }> apply ih₁ app.h₁ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ'
exact hi All goals completed! 🐙
· app.h₂ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₂✝) }> apply ih₂ app.h₂ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ'
exact hi All goals completed! 🐙
| tru => tru Γ:Contextt:Tmτ:TyΓ✝:ContextΓ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ true ⦂ Bool }> constructor All goals completed! 🐙
| fls => fls Γ:Contextt:Tmτ:TyΓ✝:ContextΓ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ false ⦂ Bool }> constructor All goals completed! 🐙
| ite _ _ _ _ _ _ _ _ ih₁ ih₂ ih₃ => ite Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Bool }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>ih₃:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ if t₁✝ then t₂✝ else t₃✝ ⦂ ~(T₁✝) }>
constructor ite.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Bool }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>ih₃:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Bool }>ite.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Bool }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>ih₃:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>ite.h₃ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Bool }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>ih₃:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>
· ite.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Bool }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>ih₃:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Bool }> apply ih₁ ite.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Bool }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>ih₃:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ'
exact hi All goals completed! 🐙
· ite.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Bool }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>ih₃:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₁✝) }> apply ih₂ ite.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Bool }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>ih₃:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ'
exact hi All goals completed! 🐙
· ite.h₃ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Bool }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>ih₃:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(T₁✝) }> apply ih₃ ite.h₃ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Bool }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>ih₃:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ'
exact hi All goals completed! 🐙
Through judicious use of apply_rules, we can heavily automate this proof.
The tactic after with is applied to every case of the induction
and handles all the cases using apply_rules's automation.
We must give the tactic access to all the HasType constructors and the
PartialMap.update_subset lemma for this to work:
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 StlcTyping All goals completed! 🐙)
The following simple corollary is what we actually need below.
theorem weakening_empty {Γ : Context} {t : Tm} {τ : Ty} (ht : <{ ∅ ⊢ ~t ⦂ ~τ }>) :
<{ ~Γ ⊢ ~t ⦂ ~τ }> := by Γ:Contextt:Tmτ:Tyht:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>
apply weakening (Γ := ∅) hi Γ:Contextt:Tmτ:Tyht:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ ∅ ⊆ Γht Γ:Contextt:Tmτ:Tyht:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ∅ ⊢ ~(t) ⦂ ~(τ) }>
-- this is the "manual" way to show that the empty context is a subset of any context:
-- show that a 'lookup' in it is impossible.
· hi Γ:Contextt:Tmτ:Tyht:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ ∅ ⊆ Γ intros x b contra hi Γ:Contextt:Tmτ:Tyht:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>x:Stringb:Tycontra:∅[x] = some b⊢ Γ[x] = some b
contradiction All goals completed! 🐙
· ht Γ:Contextt:Tmτ:Tyht:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ∅ ⊢ ~(t) ⦂ ~(τ) }> assumption All goals completed! 🐙
6.3.2. The Substitution Lemma
Now we come to the conceptual heart of the proof that reduction preserves types — namely, the observation that substitution preserves types.
Formally, the so-called substitution lemma says this:
Suppose we have a term t with a free variable x, and suppose
we've assigned a type τ to t under the assumption that x has
some type τ'. Also, suppose that we have some other term v and
that we've shown that v has type τ'. Then, since v satisfies
the assumption we made about x when typing t, we can
substitute v for each of the occurrences of x in t and
obtain a new term that still has type τ.
theorem substitution_preserves_typing (Γ : Context) (x : String) (τ' : Ty)
(t v : Tm) (τ : Ty)
(hτ : <{ ~x ↦ ~τ' ; ~Γ ⊢ ~t ⦂ ~τ }>) (hv : <{ ∅ ⊢ ~v ⦂ ~τ' }>) :
<{ ~Γ ⊢ [~x := ~v] ~t ⦂ ~τ }> := by Γ:Contextx:Stringτ':Tyt:Tmv:Tmτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>hv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>⊢ <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>
-- By induction on `t`; in each case we get at the derivation of `hτ`.
induction t generalizing Γ τ with
| var y => var x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(Stlc.Tm.var y) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ) }>
cases hτ with
| var _ _ _ h => var.var x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τ⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ) }>
by_cases hxy : x = y pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τhxy:x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ) }>neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ) }>
· pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τhxy:x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ) }> subst hxy pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[x] = some τ⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var x) ⦂ ~(τ) }>
rw [PartialMap.update_eq pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τ⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var x) ⦂ ~(τ) }>] at h pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τ⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var x) ⦂ ~(τ) }>
rw [subst_var_eq pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τ⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ) }>] pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τ⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ) }>
have hτ'τ : τ' = τ := by Γ:Contextx:Stringτ':Tyt:Tmv:Tmτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>hv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>⊢ <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>
apply Option.some.inj x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τ⊢ some τ' = some τ
exact h pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τhτ'τ:τ' = τ⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ) }>
subst hτ'τ pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contexth:some τ' = some τ'⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ') }>
apply weakening_empty pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contexth:some τ' = some τ'⊢ <{ ∅ ⊢ ~(v) ⦂ ~(τ') }>
exact hv All goals completed! 🐙
· neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ) }> rw [PartialMap.update_neq hxy neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ) }>] at h neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ) }>
rw [subst_var_ne _ _ _ hxy neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ ~(Stlc.Tm.var y) ⦂ ~(τ) }>] neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ ~(Stlc.Tm.var y) ⦂ ~(τ) }>
constructor neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τhxy:¬x = y⊢ Γ[y] = some τ
exact h All goals completed! 🐙
| app t₁ t₂ ih₁ ih₂ => app x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ t₁ t₂ ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] (t₁ t₂) ⦂ ~(τ) }>
cases hτ with
| app _ _ _ _ _ h₁ h₂ => app.app x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:TyT₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(T₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ T₂✝ → τ }>⊢ <{ ~(Γ) ⊢ [~x := v] (t₁ t₂) ⦂ ~(τ) }>
rw [subst_app app.app x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:TyT₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(T₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ T₂✝ → τ }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ [~x := v] t₂ ⦂ ~(τ) }>] app.app x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:TyT₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(T₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ T₂✝ → τ }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ [~x := v] t₂ ⦂ ~(τ) }>
constructor app.app.h₁ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:TyT₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(T₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ T₂✝ → τ }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~?app.app.T₂ → τ }>app.app.h₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:TyT₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(T₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ T₂✝ → τ }>⊢ <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(?app.app.T₂) }>app.app.T₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:TyT₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(T₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ T₂✝ → τ }>⊢ Ty
· app.app.h₁ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:TyT₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(T₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ T₂✝ → τ }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~?app.app.T₂ → τ }> apply ih₁ app.app.h₁ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:TyT₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(T₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ T₂✝ → τ }>⊢ <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~?app.app.T₂ → τ }>
exact h₁ All goals completed! 🐙
· app.app.h₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:TyT₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(T₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ T₂✝ → τ }>⊢ <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(T₂✝) }> apply ih₂ app.app.h₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:TyT₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(T₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ T₂✝ → τ }>⊢ <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(T₂✝) }>
exact h₂ All goals completed! 🐙
| abs y σ t₁ ih => abs x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ λ ~y : σ . t₁ ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : σ . t₁) ⦂ ~(τ) }>
cases hτ with
| abs _ _ _ _ _ h => abs.abs x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(y →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : σ . t₁) ⦂ σ → T₁✝ }>
by_cases hxy : x = y pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(y →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>hxy:x = y⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : σ . t₁) ⦂ σ → T₁✝ }>neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(y →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>hxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : σ . t₁) ⦂ σ → T₁✝ }>
· pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(y →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>hxy:x = y⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : σ . t₁) ⦂ σ → T₁✝ }> subst hxy pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(x →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~x : σ . t₁) ⦂ σ → T₁✝ }>
rw [subst_abs_eq pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(x →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>⊢ <{ ~(Γ) ⊢ λ ~x : σ . t₁ ⦂ σ → T₁✝ }>] pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(x →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>⊢ <{ ~(Γ) ⊢ λ ~x : σ . t₁ ⦂ σ → T₁✝ }>
rw [PartialMap.update_shadow pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(x →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>⊢ <{ ~(Γ) ⊢ λ ~x : σ . t₁ ⦂ σ → T₁✝ }>] at h pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(x →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>⊢ <{ ~(Γ) ⊢ λ ~x : σ . t₁ ⦂ σ → T₁✝ }>
constructor pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(x →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>⊢ <{ ~(x →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>
exact h All goals completed! 🐙
· neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(y →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>hxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : σ . t₁) ⦂ σ → T₁✝ }> rw [subst_abs_ne _ _ _ _ _ hxy neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(y →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>hxy:¬x = y⊢ <{ ~(Γ) ⊢ λ ~y : σ . [~x := v] t₁ ⦂ σ → T₁✝ }>] neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(y →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>hxy:¬x = y⊢ <{ ~(Γ) ⊢ λ ~y : σ . [~x := v] t₁ ⦂ σ → T₁✝ }>
rw [PartialMap.update_permute (Ne.symm hxy) neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(x →ₚ τ' ; y →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>hxy:¬x = y⊢ <{ ~(Γ) ⊢ λ ~y : σ . [~x := v] t₁ ⦂ σ → T₁✝ }>] at h neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(x →ₚ τ' ; y →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>hxy:¬x = y⊢ <{ ~(Γ) ⊢ λ ~y : σ . [~x := v] t₁ ⦂ σ → T₁✝ }>
constructor neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(x →ₚ τ' ; y →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>hxy:¬x = y⊢ <{ ~(y →ₚ σ ; Γ) ⊢ [~x := v] t₁ ⦂ ~(T₁✝) }>
apply ih neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(x →ₚ τ' ; y →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>hxy:¬x = y⊢ <{ ~(x →ₚ τ' ; y →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>
exact h All goals completed! 🐙
| tru => tru x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ true ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] true ⦂ ~(τ) }>
cases hτ with
| tru => tru.tru x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Context⊢ <{ ~(Γ) ⊢ [~x := v] true ⦂ Bool }>
rw [subst_tru tru.tru x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Context⊢ <{ ~(Γ) ⊢ true ⦂ Bool }>] tru.tru x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Context⊢ <{ ~(Γ) ⊢ true ⦂ Bool }>
constructor All goals completed! 🐙
| fls => fls x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ false ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] false ⦂ ~(τ) }>
cases hτ with
| fls => fls.fls x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Context⊢ <{ ~(Γ) ⊢ [~x := v] false ⦂ Bool }>
rw [subst_fls fls.fls x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Context⊢ <{ ~(Γ) ⊢ false ⦂ Bool }>] fls.fls x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Context⊢ <{ ~(Γ) ⊢ false ⦂ Bool }>
constructor All goals completed! 🐙
| ite c t e ihc iht ihe => ite x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>c:Tmt:Tme:Tmihc:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] c ⦂ ~(τ) }>iht:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>ihe:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] e ⦂ ~(τ) }>Γ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ if c then t else e ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] (if c then t else e) ⦂ ~(τ) }>
cases hτ with
| ite _ _ _ _ _ h₁ h₂ h₃ => ite.ite x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>c:Tmt:Tme:Tmihc:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] c ⦂ ~(τ) }>iht:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>ihe:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] e ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ Bool }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] (if c then t else e) ⦂ ~(τ) }>
rw [subst_ite ite.ite x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>c:Tmt:Tme:Tmihc:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] c ⦂ ~(τ) }>iht:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>ihe:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] e ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ Bool }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ if [~x := v] c then [~x := v] t else [~x := v] e ⦂ ~(τ) }>] ite.ite x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>c:Tmt:Tme:Tmihc:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] c ⦂ ~(τ) }>iht:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>ihe:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] e ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ Bool }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ if [~x := v] c then [~x := v] t else [~x := v] e ⦂ ~(τ) }>
constructor ite.ite.h₁ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>c:Tmt:Tme:Tmihc:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] c ⦂ ~(τ) }>iht:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>ihe:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] e ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ Bool }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] c ⦂ Bool }>ite.ite.h₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>c:Tmt:Tme:Tmihc:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] c ⦂ ~(τ) }>iht:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>ihe:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] e ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ Bool }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>ite.ite.h₃ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>c:Tmt:Tme:Tmihc:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] c ⦂ ~(τ) }>iht:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>ihe:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] e ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ Bool }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] e ⦂ ~(τ) }>
· ite.ite.h₁ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>c:Tmt:Tme:Tmihc:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] c ⦂ ~(τ) }>iht:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>ihe:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] e ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ Bool }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] c ⦂ Bool }> apply ihc ite.ite.h₁ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>c:Tmt:Tme:Tmihc:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] c ⦂ ~(τ) }>iht:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>ihe:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] e ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ Bool }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }>⊢ <{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ Bool }>
exact h₁ All goals completed! 🐙
· ite.ite.h₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>c:Tmt:Tme:Tmihc:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] c ⦂ ~(τ) }>iht:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>ihe:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] e ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ Bool }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }> apply iht ite.ite.h₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>c:Tmt:Tme:Tmihc:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] c ⦂ ~(τ) }>iht:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>ihe:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] e ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ Bool }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }>⊢ <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>
exact h₂ All goals completed! 🐙
· ite.ite.h₃ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>c:Tmt:Tme:Tmihc:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] c ⦂ ~(τ) }>iht:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>ihe:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] e ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ Bool }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] e ⦂ ~(τ) }> apply ihe ite.ite.h₃ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>c:Tmt:Tme:Tmihc:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] c ⦂ ~(τ) }>iht:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>ihe:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] e ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(c) ⦂ Bool }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }>⊢ <{ ~(x →ₚ τ' ; Γ) ⊢ ~(e) ⦂ ~(τ) }>
exact h₃ All goals completed! 🐙
The substitution lemma can be viewed as a kind of "commutation
property." Intuitively, it says that substitution and typing can
be done in either order: we can either assign types to the terms
t and v separately (under suitable contexts) and then combine
them using substitution, or we can substitute first and then
assign a type to [x:=v] t; the result is the same either
way.
Proof: We show, by induction on t, that for all τ and
Γ, if x ↦ τ' ; Γ ⊢ t ⦂ τ and ∅ ⊢ v ⦂ τ', then
Γ ⊢ [x:=v]t ⦂ τ.
-
If
tis a variable there are two cases to consider, depending on whethertisxor some other variable.-
If
t = x, then from the fact thatx ↦ τ' ; Γ ⊢ x ⦂ τwe conclude thatτ' = τ. We must show that[x:=v]x = vhas typeτunderΓ, given the assumption thatvhas typeτ' = τunder the empty context. This follows from the weakening lemma. -
If
tis some variableythat is not equal tox, then we need only note thatyhas the same type underx ↦ τ' ; Γas underΓ.
-
-
If
tis an abstractionλy:σ. t₀, thenτ = σ → τ₁and the IH tells us, for allΓ'andτ₀, that ifx ↦ τ' ; Γ' ⊢ t₀ ⦂ τ₀, thenΓ' ⊢ [x:=v]t₀ ⦂ τ₀. Moreover, by inspecting the typing rules we see it must be the case thaty ↦ σ ; x ↦ τ' ; Γ ⊢ t₀ ⦂ τ₁.The substitution in the conclusion behaves differently depending on whether
xandyare the same variable.First, suppose
x = y. Then, by the definition of substitution,[x:=v]t = t, so we just need to showΓ ⊢ t ⦂ τ. UsingHasType.abs, we need to show thaty ↦ σ ; Γ ⊢ t₀ ⦂ τ₁. But we knowy ↦ σ ; x ↦ τ' ; Γ ⊢ t₀ ⦂ τ₁, and the claim follows sincex = y.Second, suppose
x ≠ y. Again, usingHasType.abs, we need to show thaty ↦ σ ; Γ ⊢ [x:=v]t₀ ⦂ τ₁. Sincex ≠ y, we havey ↦ σ ; x ↦ τ' ; Γ = x ↦ τ' ; y ↦ σ ; Γ. So we havex ↦ τ' ; y ↦ σ ; Γ ⊢ t₀ ⦂ τ₁. Then, the IH applies (takingΓ' = y ↦ σ ; Γ), giving usy ↦ σ ; Γ ⊢ [x:=v]t₀ ⦂ τ₁, as required. -
If
tis an applicationt₁ t₂, the result follows straightforwardly from the definition of substitution and the induction hypotheses. -
The remaining cases are similar to the application case.
One technical subtlety in the statement of the above lemma is that
we assume v has type τ' in the empty context — in other
words, we assume v is closed. (Since we are using a simple
definition of substitution that is not capture-avoiding, it doesn't
make sense to substitute non-closed terms into other terms.
Fortunately, closed terms are all we need!)
Show that substitutionpreservestyping can also be proved by induction on typing derivations instead of induction on terms.
theorem substitution_preserves_typing_from_typing_ind (Γ : Context) (x : String) (τ' : Ty)
(t v : Tm) (τ : Ty)
(hτ : <{ ~x ↦ ~τ' ; ~Γ ⊢ ~t ⦂ ~τ }>) (hv : <{ ∅ ⊢ ~v ⦂ ~τ' }>) :
<{ ~Γ ⊢ [~x := ~v] ~t ⦂ ~τ }> := by Γ:Contextx:Stringτ':Tyt:Tmv:Tmτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>hv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>⊢ <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>
solution!
generalize hΓ : (x →ₚ τ' ; Γ) = Γ₀ at hτ Γ:Contextx:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyhΓ:x →ₚ τ' ; Γ = Γ₀hτ:<{ ~(Γ₀) ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>
induction hτ generalizing Γ with
| var _ y τ₁ h => var x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:Contexty:Stringτ₁:Tyh:Γ✝[y] = some τ₁Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ₁) }>
subst hΓ var x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:Stringτ₁:TyΓ:Contexth:(x →ₚ τ' ; Γ)[y] = some τ₁⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ₁) }>
by_cases hxy : x = y pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:Stringτ₁:TyΓ:Contexth:(x →ₚ τ' ; Γ)[y] = some τ₁hxy:x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ₁) }>neg x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:Stringτ₁:TyΓ:Contexth:(x →ₚ τ' ; Γ)[y] = some τ₁hxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ₁) }>
· pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:Stringτ₁:TyΓ:Contexth:(x →ₚ τ' ; Γ)[y] = some τ₁hxy:x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ₁) }> subst hxy pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyτ₁:TyΓ:Contexth:(x →ₚ τ' ; Γ)[x] = some τ₁⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var x) ⦂ ~(τ₁) }>
rw [PartialMap.update_eq pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyτ₁:TyΓ:Contexth:some τ' = some τ₁⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var x) ⦂ ~(τ₁) }>] at h pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyτ₁:TyΓ:Contexth:some τ' = some τ₁⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var x) ⦂ ~(τ₁) }>
rw [subst_var_eq pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyτ₁:TyΓ:Contexth:some τ' = some τ₁⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ₁) }>] pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyτ₁:TyΓ:Contexth:some τ' = some τ₁⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ₁) }>
have hτ'τ : τ' = τ₁ := by Γ:Contextx:Stringτ':Tyt:Tmv:Tmτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>hv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>⊢ <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>
apply Option.some.inj x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyτ₁:TyΓ:Contexth:some τ' = some τ₁⊢ some τ' = some τ₁
exact h pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyτ₁:TyΓ:Contexth:some τ' = some τ₁hτ'τ:τ' = τ₁⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ₁) }>
subst hτ'τ pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ:Contexth:some τ' = some τ'⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ') }>
apply weakening_empty pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ:Contexth:some τ' = some τ'⊢ <{ ∅ ⊢ ~(v) ⦂ ~(τ') }>
exact hv All goals completed! 🐙
· neg x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:Stringτ₁:TyΓ:Contexth:(x →ₚ τ' ; Γ)[y] = some τ₁hxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ₁) }> rw [PartialMap.update_neq hxy neg x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:Stringτ₁:TyΓ:Contexth:Γ[y] = some τ₁hxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ₁) }>] at h neg x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:Stringτ₁:TyΓ:Contexth:Γ[y] = some τ₁hxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ₁) }>
rw [subst_var_ne _ _ _ hxy neg x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:Stringτ₁:TyΓ:Contexth:Γ[y] = some τ₁hxy:¬x = y⊢ <{ ~(Γ) ⊢ ~(Stlc.Tm.var y) ⦂ ~(τ₁) }>] neg x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:Stringτ₁:TyΓ:Contexth:Γ[y] = some τ₁hxy:¬x = y⊢ <{ ~(Γ) ⊢ ~(Stlc.Tm.var y) ⦂ ~(τ₁) }>
constructor neg x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:Stringτ₁:TyΓ:Contexth:Γ[y] = some τ₁hxy:¬x = y⊢ Γ[y] = some τ₁
exact h All goals completed! 🐙
| abs _ y _ _ _ hb ih => abs x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmhb:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ : Context), x →ₚ τ' ; Γ = y →ₚ T₂✝ ; Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : T₂✝ . t₁✝) ⦂ T₂✝ → T₁✝ }>
subst hΓ abs x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:StringT₁✝:TyT₂✝:Tyt₁✝:TmΓ:Contexthb:<{ ~(y →ₚ T₂✝ ; x →ₚ τ' ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ_1 : Context), x →ₚ τ' ; Γ_1 = y →ₚ T₂✝ ; x →ₚ τ' ; Γ → <{ ~(Γ_1) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : T₂✝ . t₁✝) ⦂ T₂✝ → T₁✝ }>
by_cases hxy : x = y pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:StringT₁✝:TyT₂✝:Tyt₁✝:TmΓ:Contexthb:<{ ~(y →ₚ T₂✝ ; x →ₚ τ' ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ_1 : Context), x →ₚ τ' ; Γ_1 = y →ₚ T₂✝ ; x →ₚ τ' ; Γ → <{ ~(Γ_1) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>hxy:x = y⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : T₂✝ . t₁✝) ⦂ T₂✝ → T₁✝ }>neg x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:StringT₁✝:TyT₂✝:Tyt₁✝:TmΓ:Contexthb:<{ ~(y →ₚ T₂✝ ; x →ₚ τ' ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ_1 : Context), x →ₚ τ' ; Γ_1 = y →ₚ T₂✝ ; x →ₚ τ' ; Γ → <{ ~(Γ_1) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>hxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : T₂✝ . t₁✝) ⦂ T₂✝ → T₁✝ }>
· pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:StringT₁✝:TyT₂✝:Tyt₁✝:TmΓ:Contexthb:<{ ~(y →ₚ T₂✝ ; x →ₚ τ' ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ_1 : Context), x →ₚ τ' ; Γ_1 = y →ₚ T₂✝ ; x →ₚ τ' ; Γ → <{ ~(Γ_1) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>hxy:x = y⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : T₂✝ . t₁✝) ⦂ T₂✝ → T₁✝ }> subst hxy pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyT₁✝:TyT₂✝:Tyt₁✝:TmΓ:Contexthb:<{ ~(x →ₚ T₂✝ ; x →ₚ τ' ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ_1 : Context), x →ₚ τ' ; Γ_1 = x →ₚ T₂✝ ; x →ₚ τ' ; Γ → <{ ~(Γ_1) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~x : T₂✝ . t₁✝) ⦂ T₂✝ → T₁✝ }>
rw [subst_abs_eq pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyT₁✝:TyT₂✝:Tyt₁✝:TmΓ:Contexthb:<{ ~(x →ₚ T₂✝ ; x →ₚ τ' ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ_1 : Context), x →ₚ τ' ; Γ_1 = x →ₚ T₂✝ ; x →ₚ τ' ; Γ → <{ ~(Γ_1) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>⊢ <{ ~(Γ) ⊢ λ ~x : T₂✝ . t₁✝ ⦂ T₂✝ → T₁✝ }>] pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyT₁✝:TyT₂✝:Tyt₁✝:TmΓ:Contexthb:<{ ~(x →ₚ T₂✝ ; x →ₚ τ' ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ_1 : Context), x →ₚ τ' ; Γ_1 = x →ₚ T₂✝ ; x →ₚ τ' ; Γ → <{ ~(Γ_1) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>⊢ <{ ~(Γ) ⊢ λ ~x : T₂✝ . t₁✝ ⦂ T₂✝ → T₁✝ }>
rw [PartialMap.update_shadow pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyT₁✝:TyT₂✝:Tyt₁✝:TmΓ:Contexthb:<{ ~(x →ₚ T₂✝ ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ_1 : Context), x →ₚ τ' ; Γ_1 = x →ₚ T₂✝ ; x →ₚ τ' ; Γ → <{ ~(Γ_1) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>⊢ <{ ~(Γ) ⊢ λ ~x : T₂✝ . t₁✝ ⦂ T₂✝ → T₁✝ }>] at hb pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyT₁✝:TyT₂✝:Tyt₁✝:TmΓ:Contexthb:<{ ~(x →ₚ T₂✝ ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ_1 : Context), x →ₚ τ' ; Γ_1 = x →ₚ T₂✝ ; x →ₚ τ' ; Γ → <{ ~(Γ_1) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>⊢ <{ ~(Γ) ⊢ λ ~x : T₂✝ . t₁✝ ⦂ T₂✝ → T₁✝ }>
constructor pos x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyT₁✝:TyT₂✝:Tyt₁✝:TmΓ:Contexthb:<{ ~(x →ₚ T₂✝ ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ_1 : Context), x →ₚ τ' ; Γ_1 = x →ₚ T₂✝ ; x →ₚ τ' ; Γ → <{ ~(Γ_1) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>⊢ <{ ~(x →ₚ T₂✝ ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>
exact hb All goals completed! 🐙
· neg x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:StringT₁✝:TyT₂✝:Tyt₁✝:TmΓ:Contexthb:<{ ~(y →ₚ T₂✝ ; x →ₚ τ' ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ_1 : Context), x →ₚ τ' ; Γ_1 = y →ₚ T₂✝ ; x →ₚ τ' ; Γ → <{ ~(Γ_1) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>hxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : T₂✝ . t₁✝) ⦂ T₂✝ → T₁✝ }> rw [subst_abs_ne _ _ _ _ _ hxy neg x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:StringT₁✝:TyT₂✝:Tyt₁✝:TmΓ:Contexthb:<{ ~(y →ₚ T₂✝ ; x →ₚ τ' ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ_1 : Context), x →ₚ τ' ; Γ_1 = y →ₚ T₂✝ ; x →ₚ τ' ; Γ → <{ ~(Γ_1) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>hxy:¬x = y⊢ <{ ~(Γ) ⊢ λ ~y : T₂✝ . [~x := v] t₁✝ ⦂ T₂✝ → T₁✝ }>] neg x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:StringT₁✝:TyT₂✝:Tyt₁✝:TmΓ:Contexthb:<{ ~(y →ₚ T₂✝ ; x →ₚ τ' ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ_1 : Context), x →ₚ τ' ; Γ_1 = y →ₚ T₂✝ ; x →ₚ τ' ; Γ → <{ ~(Γ_1) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>hxy:¬x = y⊢ <{ ~(Γ) ⊢ λ ~y : T₂✝ . [~x := v] t₁✝ ⦂ T₂✝ → T₁✝ }>
constructor neg x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:StringT₁✝:TyT₂✝:Tyt₁✝:TmΓ:Contexthb:<{ ~(y →ₚ T₂✝ ; x →ₚ τ' ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ_1 : Context), x →ₚ τ' ; Γ_1 = y →ₚ T₂✝ ; x →ₚ τ' ; Γ → <{ ~(Γ_1) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>hxy:¬x = y⊢ <{ ~(y →ₚ T₂✝ ; Γ) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>
apply ih neg x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:StringT₁✝:TyT₂✝:Tyt₁✝:TmΓ:Contexthb:<{ ~(y →ₚ T₂✝ ; x →ₚ τ' ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ_1 : Context), x →ₚ τ' ; Γ_1 = y →ₚ T₂✝ ; x →ₚ τ' ; Γ → <{ ~(Γ_1) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>hxy:¬x = y⊢ x →ₚ τ' ; y →ₚ T₂✝ ; Γ = y →ₚ T₂✝ ; x →ₚ τ' ; Γ
apply PartialMap.update_permute neg x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:StringT₁✝:TyT₂✝:Tyt₁✝:TmΓ:Contexthb:<{ ~(y →ₚ T₂✝ ; x →ₚ τ' ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ_1 : Context), x →ₚ τ' ; Γ_1 = y →ₚ T₂✝ ; x →ₚ τ' ; Γ → <{ ~(Γ_1) ⊢ [~x := v] t₁✝ ⦂ ~(T₁✝) }>hxy:¬x = y⊢ x ≠ y
exact hxy All goals completed! 🐙
| app _ _ _ _ _ _ _ ih₁ ih₂ => app x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₂✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] (t₁✝ t₂✝) ⦂ ~(T₁✝) }>
rw [subst_app app x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₂✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] t₁✝ [~x := v] t₂✝ ⦂ ~(T₁✝) }>] app x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₂✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] t₁✝ [~x := v] t₂✝ ⦂ ~(T₁✝) }>
constructor app.h₁ x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₂✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ ~?app.T₂ → T₁✝ }>app.h₂ x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₂✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(?app.T₂) }>app.T₂ x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₂✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ Ty
· app.h₁ x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₂✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ ~?app.T₂ → T₁✝ }> apply ih₁ app.h₁ x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₂✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ x →ₚ τ' ; Γ = Γ✝
exact hΓ All goals completed! 🐙
· app.h₂ x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₂✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₂✝) }> apply ih₂ app.h₂ x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₂✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ x →ₚ τ' ; Γ = Γ✝
exact hΓ All goals completed! 🐙
| tru => tru x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextΓ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] true ⦂ Bool }>
rw [subst_tru tru x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextΓ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ true ⦂ Bool }>] tru x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextΓ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ true ⦂ Bool }>
constructor All goals completed! 🐙
| fls => fls x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextΓ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] false ⦂ Bool }>
rw [subst_fls fls x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextΓ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ false ⦂ Bool }>] fls x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextΓ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ false ⦂ Bool }>
constructor All goals completed! 🐙
| ite _ _ _ _ _ _ _ _ ih₁ ih₂ ih₃ => ite x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ Bool }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₁✝) }>ih₃:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₃✝ ⦂ ~(T₁✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] (if t₁✝ then t₂✝ else t₃✝) ⦂ ~(T₁✝) }>
rw [subst_ite ite x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ Bool }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₁✝) }>ih₃:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₃✝ ⦂ ~(T₁✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ if [~x := v] t₁✝ then [~x := v] t₂✝ else [~x := v] t₃✝ ⦂ ~(T₁✝) }>] ite x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ Bool }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₁✝) }>ih₃:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₃✝ ⦂ ~(T₁✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ if [~x := v] t₁✝ then [~x := v] t₂✝ else [~x := v] t₃✝ ⦂ ~(T₁✝) }>
constructor ite.h₁ x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ Bool }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₁✝) }>ih₃:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₃✝ ⦂ ~(T₁✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ Bool }>ite.h₂ x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ Bool }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₁✝) }>ih₃:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₃✝ ⦂ ~(T₁✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₁✝) }>ite.h₃ x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ Bool }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₁✝) }>ih₃:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₃✝ ⦂ ~(T₁✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] t₃✝ ⦂ ~(T₁✝) }>
· ite.h₁ x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ Bool }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₁✝) }>ih₃:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₃✝ ⦂ ~(T₁✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ Bool }> apply ih₁ ite.h₁ x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ Bool }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₁✝) }>ih₃:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₃✝ ⦂ ~(T₁✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ x →ₚ τ' ; Γ = Γ✝
exact hΓ All goals completed! 🐙
· ite.h₂ x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ Bool }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₁✝) }>ih₃:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₃✝ ⦂ ~(T₁✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₁✝) }> apply ih₂ ite.h₂ x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ Bool }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₁✝) }>ih₃:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₃✝ ⦂ ~(T₁✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ x →ₚ τ' ; Γ = Γ✝
exact hΓ All goals completed! 🐙
· ite.h₃ x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ Bool }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₁✝) }>ih₃:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₃✝ ⦂ ~(T₁✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] t₃✝ ⦂ ~(T₁✝) }> apply ih₃ ite.h₃ x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>ih₁:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₁✝ ⦂ Bool }>ih₂:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₂✝ ⦂ ~(T₁✝) }>ih₃:∀ (Γ : Context), x →ₚ τ' ; Γ = Γ✝ → <{ ~(Γ) ⊢ [~x := v] t₃✝ ⦂ ~(T₁✝) }>Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ x →ₚ τ' ; Γ = Γ✝
exact hΓ All goals completed! 🐙
6.3.3. Main Theorem
We now have the ingredients we need to prove preservation: if a
closed, well-typed term t has type τ and takes a step to t',
then t' is also a closed term with type τ. In other words,
the small-step reduction relation preserves types.
theorem preservation (t t' : Tm) (τ : Ty)
(hτ : <{ ∅ ⊢ ~t ⦂ ~τ }>) (hs : t ⟶ t') : <{ ∅ ⊢ ~t' ⦂ ~τ }> := by t:Tmt':Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>hs:t ⟶ t'⊢ <{ ∅ ⊢ ~(t') ⦂ ~(τ) }>
generalize hΓ : (∅ : Context) = Γ at hτ t:Tmt':Tmτ:Tyhs:t ⟶ t'Γ:ContexthΓ:∅ = Γhτ:<{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ ~(t') ⦂ ~(τ) }>
induction hτ generalizing t' with
| var => var t:Tmτ:TyΓ:ContextΓ✝:Contextx✝:StringT₁✝:Tyh✝:Γ✝[x✝] = some T₁✝t':Tmhs:Stlc.Tm.var x✝ ⟶ t'hΓ:∅ = Γ✝⊢ <{ ~(Γ✝) ⊢ ~(t') ⦂ ~(T₁✝) }> cases hs All goals completed! 🐙
| abs => abs t:Tmτ:TyΓ:ContextΓ✝:Contextx✝:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>h_ih✝:∀ (t' : Tm), t₁✝ ⟶ t' → ∅ = x✝ →ₚ T₂✝ ; Γ✝ → <{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t') ⦂ ~(T₁✝) }>t':Tmhs:<{ λ ~x✝ : T₂✝ . t₁✝ }> ⟶ t'hΓ:∅ = Γ✝⊢ <{ ~(Γ✝) ⊢ ~(t') ⦂ T₂✝ → T₁✝ }> cases hs All goals completed! 🐙
| tru => tru t:Tmτ:TyΓ:ContextΓ✝:Contextt':Tmhs:<{ true }> ⟶ t'hΓ:∅ = Γ✝⊢ <{ ~(Γ✝) ⊢ ~(t') ⦂ Bool }> cases hs All goals completed! 🐙
| fls => fls t:Tmτ:TyΓ:ContextΓ✝:Contextt':Tmhs:<{ false }> ⟶ t'hΓ:∅ = Γ✝⊢ <{ ~(Γ✝) ⊢ ~(t') ⦂ Bool }> cases hs All goals completed! 🐙
| app Γ τ₁ τ₂ t₁ t₂ h₁ h₂ ih₁ ih₂ => app t:Tmτ:TyΓ✝:ContextΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ~(Γ) ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ~(Γ) ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = Γ → <{ ~(Γ) ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = Γ → <{ ~(Γ) ⊢ ~(t') ⦂ ~(τ₂) }>t':Tmhs:<{ t₁ t₂ }> ⟶ t'hΓ:∅ = Γ⊢ <{ ~(Γ) ⊢ ~(t') ⦂ ~(τ₁) }>
subst hΓ app t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmt':Tmhs:<{ t₁ t₂ }> ⟶ t'h₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>⊢ <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>
cases hs with
| appAbs _ _ _ _ _ => app.appAbs t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>x✝:StringT✝:Tyt✝:Tmh₁:<{ ∅ ⊢ λ ~x✝ : T✝ . t✝ ⦂ τ₂ → τ₁ }>ih₁:∀ (t' : Tm), <{ λ ~x✝ : T✝ . t✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>hv✝:t₂.IsValue⊢ <{ ∅ ⊢ [~x✝ := t₂] t✝ ⦂ ~(τ₁) }>
-- The one interesting case: the desired result is the substitution lemma.
cases h₁ with
| abs _ _ _ _ _ hb => app.appAbs.abs t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>x✝:Stringt✝:Tmhv✝:t₂.IsValueih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂ . t✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>hb:<{ ~(x✝ →ₚ τ₂) ⊢ ~(t✝) ⦂ ~(τ₁) }>⊢ <{ ∅ ⊢ [~x✝ := t₂] t✝ ⦂ ~(τ₁) }>
apply substitution_preserves_typing app.appAbs.abs.hτ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>x✝:Stringt✝:Tmhv✝:t₂.IsValueih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂ . t✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>hb:<{ ~(x✝ →ₚ τ₂) ⊢ ~(t✝) ⦂ ~(τ₁) }>⊢ <{ ~(x✝ →ₚ ?app.appAbs.abs.τ') ⊢ ~(t✝) ⦂ ~(τ₁) }>app.appAbs.abs.hv t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>x✝:Stringt✝:Tmhv✝:t₂.IsValueih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂ . t✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>hb:<{ ~(x✝ →ₚ τ₂) ⊢ ~(t✝) ⦂ ~(τ₁) }>⊢ <{ ∅ ⊢ ~(t₂) ⦂ ~(?app.appAbs.abs.τ') }>app.appAbs.abs.τ' t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>x✝:Stringt✝:Tmhv✝:t₂.IsValueih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂ . t✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>hb:<{ ~(x✝ →ₚ τ₂) ⊢ ~(t✝) ⦂ ~(τ₁) }>⊢ Ty
· app.appAbs.abs.hτ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>x✝:Stringt✝:Tmhv✝:t₂.IsValueih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂ . t✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>hb:<{ ~(x✝ →ₚ τ₂) ⊢ ~(t✝) ⦂ ~(τ₁) }>⊢ <{ ~(x✝ →ₚ ?app.appAbs.abs.τ') ⊢ ~(t✝) ⦂ ~(τ₁) }> exact hb All goals completed! 🐙
· app.appAbs.abs.hv t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>x✝:Stringt✝:Tmhv✝:t₂.IsValueih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂ . t✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>hb:<{ ~(x✝ →ₚ τ₂) ⊢ ~(t✝) ⦂ ~(τ₁) }>⊢ <{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }> exact h₂ All goals completed! 🐙
| app1 _ t₁' _ h => app.app1 t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>t₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ t₁' t₂ ⦂ ~(τ₁) }>
constructor app.app1.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₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₁') ⦂ ~?app.app1.T₂ → τ₁ }>app.app1.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₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₂) ⦂ ~(?app.app1.T₂) }>app.app1.T₂ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>t₁':Tmh:t₁ ⟶ t₁'⊢ Ty
· app.app1.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₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₁') ⦂ ~?app.app1.T₂ → τ₁ }> apply ih₁ app.app1.h₁.hs t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>t₁':Tmh:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'app.app1.h₁.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₁':Tmh:t₁ ⟶ t₁'⊢ ∅ = ∅
· app.app1.h₁.hs t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>t₁':Tmh:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁' exact h All goals completed! 🐙
· app.app1.h₁.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₁':Tmh:t₁ ⟶ t₁'⊢ ∅ = ∅ rfl All goals completed! 🐙
· app.app1.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₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }> exact h₂ All goals completed! 🐙
| app2 _ _ t₂' _ h => app.app2 t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>t₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ <{ ∅ ⊢ t₁ t₂' ⦂ ~(τ₁) }>
constructor app.app2.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₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ <{ ∅ ⊢ ~(t₁) ⦂ ~?app.app2.T₂ → τ₁ }>app.app2.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₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ <{ ∅ ⊢ ~(t₂') ⦂ ~(?app.app2.T₂) }>app.app2.T₂ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>t₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ Ty
· app.app2.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₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ <{ ∅ ⊢ ~(t₁) ⦂ ~?app.app2.T₂ → τ₁ }> exact h₁ All goals completed! 🐙
· app.app2.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₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ <{ ∅ ⊢ ~(t₂') ⦂ ~(τ₂) }> apply ih₂ app.app2.h₂.hs t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>t₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ t₂ ⟶ t₂'app.app2.h₂.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₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ ∅ = ∅
· app.app2.h₂.hs t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>t₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ t₂ ⟶ t₂' exact h All goals completed! 🐙
· app.app2.h₂.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₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ ∅ = ∅ rfl All goals completed! 🐙
| ite Γ t₁ t₂ t₃ τ₁ h₁ h₂ h₃ ih₁ ih₂ ih₃ => ite t:Tmτ:TyΓ✝:ContextΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ~(Γ) ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ~(Γ) ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ~(Γ) ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = Γ → <{ ~(Γ) ⊢ ~(t') ⦂ Bool }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = Γ → <{ ~(Γ) ⊢ ~(t') ⦂ ~(τ₁) }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = Γ → <{ ~(Γ) ⊢ ~(t') ⦂ ~(τ₁) }>t':Tmhs:<{ if t₁ then t₂ else t₃ }> ⟶ t'hΓ:∅ = Γ⊢ <{ ~(Γ) ⊢ ~(t') ⦂ ~(τ₁) }>
subst hΓ ite t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyt':Tmhs:<{ if t₁ then t₂ else t₃ }> ⟶ t'h₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Bool }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>⊢ <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>
cases hs with
| ifTrue => ite.ifTrue t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmτ₁:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>h₁:<{ ∅ ⊢ true ⦂ Bool }>ih₁:∀ (t' : Tm), <{ true }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Bool }>⊢ <{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }> exact h₂ All goals completed! 🐙
| ifFalse => ite.ifFalse t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmτ₁:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>h₁:<{ ∅ ⊢ false ⦂ Bool }>ih₁:∀ (t' : Tm), <{ false }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Bool }>⊢ <{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }> exact h₃ All goals completed! 🐙
| ifStep _ t₁' _ _ h => ite.ifStep t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Bool }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>t₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ if t₁' then t₂ else t₃ ⦂ ~(τ₁) }>
constructor ite.ifStep.h₁ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Bool }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>t₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₁') ⦂ Bool }>ite.ifStep.h₂ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Bool }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>t₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>ite.ifStep.h₃ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Bool }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>t₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>
· ite.ifStep.h₁ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Bool }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>t₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₁') ⦂ Bool }> apply ih₁ ite.ifStep.h₁.hs t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Bool }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>t₁':Tmh:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'ite.ifStep.h₁.hΓ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Bool }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>t₁':Tmh:t₁ ⟶ t₁'⊢ ∅ = ∅
· ite.ifStep.h₁.hs t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Bool }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>t₁':Tmh:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁' exact h All goals completed! 🐙
· ite.ifStep.h₁.hΓ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Bool }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>t₁':Tmh:t₁ ⟶ t₁'⊢ ∅ = ∅ rfl All goals completed! 🐙
· ite.ifStep.h₂ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Bool }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>t₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }> exact h₂ All goals completed! 🐙
· ite.ifStep.h₃ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₁:Tyh₁:<{ ∅ ⊢ ~(t₁) ⦂ Bool }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₁) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Bool }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>ih₃:∀ (t' : Tm), t₃ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>t₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₃) ⦂ ~(τ₁) }> exact h₃ All goals completed! 🐙
Proof: By induction on the derivation of ∅ ⊢ t ⦂ τ.
-
We can immediately rule out
HasType.var,HasType.abs,HasType.tru, andHasType.flsas final rules in the derivation, since in each of these casestcannot take a step. -
If the last rule in the derivation is
HasType.app, thent = t₁ t₂, and there are subderivations showing that∅ ⊢ t₁ ⦂ τ₂ → τand∅ ⊢ t₂ ⦂ τ₂plus two induction hypotheses: (1)t₁ ⟶ t₁'implies∅ ⊢ t₁' ⦂ τ₂ → τand (2)t₂ ⟶ t₂'implies∅ ⊢ t₂' ⦂ τ₂. There are now three subcases to consider, one for each rule that could be used to show thatt₁ t₂takes a step tot'.-
If
t₁ t₂takes a step byStep.app1, witht₁stepping tot₁', then, by the first IH,t₁'has the same type ast₁(∅ ⊢ t₁' ⦂ τ₂ → τ), and hence byHasType.appt₁' t₂has typeτ. -
The
Step.app2case is similar, using the second IH. -
If
t₁ t₂takes a step byStep.appAbs, thent₁ = λx:τ₀. t₀andt₁ t₂steps to[x:=t₂]t₀; the desired result now follows from the substitution lemma.
-
-
If the last rule in the derivation is
HasType.ite, thent = if t₁ then t₂ else t₃, with∅ ⊢ t₁ ⦂ Bool,∅ ⊢ t₂ ⦂ τ₁, and∅ ⊢ t₃ ⦂ τ₁, and with three induction hypotheses: (1)t₁ ⟶ t₁'implies∅ ⊢ t₁' ⦂ Bool, (2)t₂ ⟶ t₂'implies∅ ⊢ t₂' ⦂ τ₁, and (3)t₃ ⟶ t₃'implies∅ ⊢ t₃' ⦂ τ₁.There are again three subcases to consider, depending on how
tsteps.-
If
tsteps tot₂ort₃byStep.ifTrueorStep.ifFalse, the result is immediate, sincet₂andt₃have the same type ast. -
Otherwise,
tsteps byStep.ifStep, and the desired conclusion follows directly from the first induction hypothesis.
-
An exercise in the Types chapter asked about the subject
expansion property for the simple language of arithmetic and
boolean expressions. This property did not hold for that language,
and it also fails for STLC. That is, it is not always the case that,
if t ⟶ t' and ∅ ⊢ t' ⦂ τ, then ∅ ⊢ t ⦂ τ.
Show this by giving a counter-example that does not involve
conditionals.
For example,
(λx:Bool → Bool. true) true is ill typed, but it evaluates
to the well-typed term true.
This solution has to be rewritten; it is unreadable.
theorem not_subject_expansion :
∃ (t t' : Tm) (τ : Ty), t ⟶ t' ∧ <{ ∅ ⊢ ~t' ⦂ ~τ }> ∧ ¬ <{ ∅ ⊢ ~t ⦂ ~τ }> := by ⊢ ∃ t t' τ, t ⟶ t' ∧ <{ ∅ ⊢ ~(t') ⦂ ~(τ) }> ∧ ¬<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>
-- Hint: for giving counterexamples in STLC, give each witness
-- with `exists <{ … }>`. This works for both terms and types, as
-- in `<{true}>` and `<{ Bool }>`.
solution!(
exists <{ (λ x : Bool → Bool . true) true }>, <{true}>, <{Bool}> ⊢ <{ (λ x : Bool → Bool . true) true }> ⟶ <{ true }> ∧
<{ ∅ ⊢ true ⦂ Bool }> ∧ ¬<{ ∅ ⊢ (λ x : Bool → Bool . true) true ⦂ Bool }>
constructor left ⊢ <{ (λ x : Bool → Bool . true) true }> ⟶ <{ true }>right ⊢ <{ ∅ ⊢ true ⦂ Bool }> ∧ ¬<{ ∅ ⊢ (λ x : Bool → Bool . true) true ⦂ Bool }>
. left ⊢ <{ (λ x : Bool → Bool . true) true }> ⟶ <{ true }> constructor left ⊢ <{ true }>.IsValue; constructor All goals completed! 🐙
. right ⊢ <{ ∅ ⊢ true ⦂ Bool }> ∧ ¬<{ ∅ ⊢ (λ x : Bool → Bool . true) true ⦂ Bool }> constructor right.left ⊢ <{ ∅ ⊢ true ⦂ Bool }>right.right ⊢ ¬<{ ∅ ⊢ (λ x : Bool → Bool . true) true ⦂ Bool }>
. right.left ⊢ <{ ∅ ⊢ true ⦂ Bool }> constructor All goals completed! 🐙
. right.right ⊢ ¬<{ ∅ ⊢ (λ x : Bool → Bool . true) true ⦂ Bool }> intro contra right.right contra:<{ ∅ ⊢ (λ x : Bool → Bool . true) true ⦂ Bool }>⊢ False
inversion contra with
| app τ h₁ h₂ =>
inversion h₂ abs h₁:<{ ∅ ⊢ true ⦂ Bool → Bool }>h✝:<{ x ↦ Bool → Bool ; ∅ ⊢ true ⦂ Bool }>⊢ False
. abs h₁:<{ ∅ ⊢ true ⦂ Bool → Bool }>h✝:<{ x ↦ Bool → Bool ; ∅ ⊢ true ⦂ Bool }>⊢ False inversion h₁ All goals completed! 🐙
)
Alternative formulation.
6.4. Type Soundness
Put progress and preservation together and show that a well-typed term can never reach a stuck state.
def Tm.IsStuck (t : Tm) : Prop := IsNormalForm Step t ∧ ¬ t.IsValue
theorem type_soundness (t t' : Tm) (τ : Ty)
(hτ : <{ ∅ ⊢ ~t ⦂ ~τ }>) (hm : t ⟶* t') : ¬ t'.IsStuck := by t:Tmt':Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>hm:t ⟶* t'⊢ ¬t'.IsStuck
intro hst t:Tmt':Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>hm:t ⟶* t'hst:t'.IsStuck⊢ False
obtain ⟨hnf, hnv⟩ := hst t:Tmt':Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>hm:t ⟶* t'hnf:IsNormalForm Step t'hnv:¬t'.IsValue⊢ False
induction hm with
| refl u => refl t:Tmt':Tmτ:Tyu:Tmhτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step uhnv:¬u.IsValue⊢ False
solution!
cases progress u τ hτ with
| inl hv => refl.inl t:Tmt':Tmτ:Tyu:Tmhτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step uhnv:¬u.IsValuehv:u.IsValue⊢ False exact hnv hv All goals completed! 🐙
| inr hs => refl.inr t:Tmt':Tmτ:Tyu:Tmhτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step uhnv:¬u.IsValuehs:∃ t', u ⟶ t'⊢ False exact hnf hs All goals completed! 🐙
| step u w z h₁ _ ih => step t:Tmt':Tmτ:Tyu:Tmw:Tmz:Tmh₁:u ⟶ wh₂✝:w ⟶* zih:<{ ∅ ⊢ ~(w) ⦂ ~(τ) }> → IsNormalForm Step z → ¬z.IsValue → Falsehτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step zhnv:¬z.IsValue⊢ False
solution!
apply ih step.hτ t:Tmt':Tmτ:Tyu:Tmw:Tmz:Tmh₁:u ⟶ wh₂✝:w ⟶* zih:<{ ∅ ⊢ ~(w) ⦂ ~(τ) }> → IsNormalForm Step z → ¬z.IsValue → Falsehτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step zhnv:¬z.IsValue⊢ <{ ∅ ⊢ ~(w) ⦂ ~(τ) }>step.hnf t:Tmt':Tmτ:Tyu:Tmw:Tmz:Tmh₁:u ⟶ wh₂✝:w ⟶* zih:<{ ∅ ⊢ ~(w) ⦂ ~(τ) }> → IsNormalForm Step z → ¬z.IsValue → Falsehτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step zhnv:¬z.IsValue⊢ IsNormalForm Step zstep.hnv t:Tmt':Tmτ:Tyu:Tmw:Tmz:Tmh₁:u ⟶ wh₂✝:w ⟶* zih:<{ ∅ ⊢ ~(w) ⦂ ~(τ) }> → IsNormalForm Step z → ¬z.IsValue → Falsehτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step zhnv:¬z.IsValue⊢ ¬z.IsValue
· step.hτ t:Tmt':Tmτ:Tyu:Tmw:Tmz:Tmh₁:u ⟶ wh₂✝:w ⟶* zih:<{ ∅ ⊢ ~(w) ⦂ ~(τ) }> → IsNormalForm Step z → ¬z.IsValue → Falsehτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step zhnv:¬z.IsValue⊢ <{ ∅ ⊢ ~(w) ⦂ ~(τ) }> apply preservation step.hτ.hτ t:Tmt':Tmτ:Tyu:Tmw:Tmz:Tmh₁:u ⟶ wh₂✝:w ⟶* zih:<{ ∅ ⊢ ~(w) ⦂ ~(τ) }> → IsNormalForm Step z → ¬z.IsValue → Falsehτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step zhnv:¬z.IsValue⊢ <{ ∅ ⊢ ~(?step.hτ.t) ⦂ ~(τ) }>step.hτ.hs t:Tmt':Tmτ:Tyu:Tmw:Tmz:Tmh₁:u ⟶ wh₂✝:w ⟶* zih:<{ ∅ ⊢ ~(w) ⦂ ~(τ) }> → IsNormalForm Step z → ¬z.IsValue → Falsehτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step zhnv:¬z.IsValue⊢ ?step.hτ.t ⟶ wstep.hτ.t t:Tmt':Tmτ:Tyu:Tmw:Tmz:Tmh₁:u ⟶ wh₂✝:w ⟶* zih:<{ ∅ ⊢ ~(w) ⦂ ~(τ) }> → IsNormalForm Step z → ¬z.IsValue → Falsehτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step zhnv:¬z.IsValue⊢ Tm
· step.hτ.hτ t:Tmt':Tmτ:Tyu:Tmw:Tmz:Tmh₁:u ⟶ wh₂✝:w ⟶* zih:<{ ∅ ⊢ ~(w) ⦂ ~(τ) }> → IsNormalForm Step z → ¬z.IsValue → Falsehτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step zhnv:¬z.IsValue⊢ <{ ∅ ⊢ ~(?step.hτ.t) ⦂ ~(τ) }> exact hτ All goals completed! 🐙
· step.hτ.hs t:Tmt':Tmτ:Tyu:Tmw:Tmz:Tmh₁:u ⟶ wh₂✝:w ⟶* zih:<{ ∅ ⊢ ~(w) ⦂ ~(τ) }> → IsNormalForm Step z → ¬z.IsValue → Falsehτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step zhnv:¬z.IsValue⊢ u ⟶ w exact h₁ All goals completed! 🐙
· step.hnf t:Tmt':Tmτ:Tyu:Tmw:Tmz:Tmh₁:u ⟶ wh₂✝:w ⟶* zih:<{ ∅ ⊢ ~(w) ⦂ ~(τ) }> → IsNormalForm Step z → ¬z.IsValue → Falsehτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step zhnv:¬z.IsValue⊢ IsNormalForm Step z exact hnf All goals completed! 🐙
· step.hnv t:Tmt':Tmτ:Tyu:Tmw:Tmz:Tmh₁:u ⟶ wh₂✝:w ⟶* zih:<{ ∅ ⊢ ~(w) ⦂ ~(τ) }> → IsNormalForm Step z → ¬z.IsValue → Falsehτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step zhnv:¬z.IsValue⊢ ¬z.IsValue exact hnv All goals completed! 🐙
6.5. Uniqueness of Types
Another nice property of the STLC is that types are unique: a given term (in a given context) has at most one type.
theorem unique_types (Γ : Context) (e : Tm) (τ τ' : Ty)
(h : <{ ~Γ ⊢ ~e ⦂ ~τ }>) (h' : <{ ~Γ ⊢ ~e ⦂ ~τ' }>) : τ = τ' := by Γ:Contexte:Tmτ:Tyτ':Tyh:<{ ~(Γ) ⊢ ~(e) ⦂ ~(τ) }>h':<{ ~(Γ) ⊢ ~(e) ⦂ ~(τ') }>⊢ τ = τ'
solution!
induction h generalizing τ' with
| var _ _ _ hx => var Γ:Contexte:Tmτ:TyΓ✝:Contextx✝:StringT₁✝:Tyhx:Γ✝[x✝] = some T₁✝τ':Tyh':<{ ~(Γ✝) ⊢ ~(Stlc.Tm.var x✝) ⦂ ~(τ') }>⊢ T₁✝ = τ'
cases h' with
| var _ _ _ hx' => var.var Γ:Contexte:Tmτ:TyΓ✝:Contextx✝:StringT₁✝:Tyhx:Γ✝[x✝] = some T₁✝τ':Tyhx':Γ✝[x✝] = some τ'⊢ T₁✝ = τ'
rw [hx var.var Γ:Contexte:Tmτ:TyΓ✝:Contextx✝:StringT₁✝:Tyhx:Γ✝[x✝] = some T₁✝τ':Tyhx':some T₁✝ = some τ'⊢ T₁✝ = τ'] at hx' var.var Γ:Contexte:Tmτ:TyΓ✝:Contextx✝:StringT₁✝:Tyhx:Γ✝[x✝] = some T₁✝τ':Tyhx':some T₁✝ = some τ'⊢ T₁✝ = τ'
injection hx' All goals completed! 🐙
| abs _ _ τ₁ _ _ _ ih => abs Γ:Contexte:Tmτ:TyΓ✝:Contextx✝:Stringτ₁:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁) }>ih:∀ (τ' : Ty), <{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ') }> → τ₁ = τ'τ':Tyh':<{ ~(Γ✝) ⊢ λ ~x✝ : T₂✝ . t₁✝ ⦂ ~(τ') }>⊢ <{ T₂✝ → τ₁ }> = τ'
cases h' with
| abs _ _ τ₁' _ _ hb' => abs.abs Γ:Contexte:Tmτ:TyΓ✝:Contextx✝:Stringτ₁:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁) }>ih:∀ (τ' : Ty), <{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ') }> → τ₁ = τ'τ₁':Tyhb':<{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁') }>⊢ <{ T₂✝ → τ₁ }> = <{ T₂✝ → τ₁' }>
have heq : τ₁ = τ₁' := by Γ:Contexte:Tmτ:Tyτ':Tyh:<{ ~(Γ) ⊢ ~(e) ⦂ ~(τ) }>h':<{ ~(Γ) ⊢ ~(e) ⦂ ~(τ') }>⊢ τ = τ'
apply ih Γ:Contexte:Tmτ:TyΓ✝:Contextx✝:Stringτ₁:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁) }>ih:∀ (τ' : Ty), <{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ') }> → τ₁ = τ'τ₁':Tyhb':<{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁') }>⊢ <{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁') }>
exact hb' abs.abs Γ:Contexte:Tmτ:TyΓ✝:Contextx✝:Stringτ₁:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁) }>ih:∀ (τ' : Ty), <{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ') }> → τ₁ = τ'τ₁':Tyhb':<{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁') }>heq:τ₁ = τ₁'⊢ <{ T₂✝ → τ₁ }> = <{ T₂✝ → τ₁' }>
rw [heq abs.abs Γ:Contexte:Tmτ:TyΓ✝:Contextx✝:Stringτ₁:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁) }>ih:∀ (τ' : Ty), <{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ') }> → τ₁ = τ'τ₁':Tyhb':<{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁') }>heq:τ₁ = τ₁'⊢ <{ T₂✝ → τ₁' }> = <{ T₂✝ → τ₁' }>] All goals completed! 🐙
| app _ _ _ _ _ _ _ ih₁ _ => app Γ:Contexte:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ (τ' : Ty), <{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ') }> → <{ T₂✝ → T₁✝ }> = τ'h₂_ih✝:∀ (τ' : Ty), <{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ') }> → T₂✝ = τ'τ':Tyh':<{ ~(Γ✝) ⊢ t₁✝ t₂✝ ⦂ ~(τ') }>⊢ T₁✝ = τ'
cases h' with
| app _ _ _ _ _ hf' _ => app.app Γ:Contexte:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝¹:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝¹:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ (τ' : Ty), <{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ') }> → <{ T₂✝ → T₁✝ }> = τ'h₂_ih✝:∀ (τ' : Ty), <{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ') }> → T₂✝ = τ'τ':TyT₂✝:Tyh₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>hf':<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → τ' }>⊢ T₁✝ = τ'
have harrow := ih₁ _ hf' app.app Γ:Contexte:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝¹:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝¹:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ (τ' : Ty), <{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ') }> → <{ T₂✝ → T₁✝ }> = τ'h₂_ih✝:∀ (τ' : Ty), <{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ') }> → T₂✝ = τ'τ':TyT₂✝:Tyh₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>hf':<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → τ' }>harrow:<{ T₂✝¹ → T₁✝ }> = <{ T₂✝ → τ' }>⊢ T₁✝ = τ'
injection harrow All goals completed! 🐙
| tru => tru Γ:Contexte:Tmτ:TyΓ✝:Contextτ':Tyh':<{ ~(Γ✝) ⊢ true ⦂ ~(τ') }>⊢ <{ Bool }> = τ' cases h' with | tru => tru.tru Γ:Contexte:Tmτ:TyΓ✝:Context⊢ <{ Bool }> = <{ Bool }> rfl All goals completed! 🐙
| fls => fls Γ:Contexte:Tmτ:TyΓ✝:Contextτ':Tyh':<{ ~(Γ✝) ⊢ false ⦂ ~(τ') }>⊢ <{ Bool }> = τ' cases h' with | fls => fls.fls Γ:Contexte:Tmτ:TyΓ✝:Context⊢ <{ Bool }> = <{ Bool }> rfl All goals completed! 🐙
| ite _ _ _ _ _ _ _ _ _ ih₂ _ => ite Γ:Contexte:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>h₁_ih✝:∀ (τ' : Ty), <{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ') }> → <{ Bool }> = τ'ih₂:∀ (τ' : Ty), <{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ') }> → T₁✝ = τ'h₃_ih✝:∀ (τ' : Ty), <{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(τ') }> → T₁✝ = τ'τ':Tyh':<{ ~(Γ✝) ⊢ if t₁✝ then t₂✝ else t₃✝ ⦂ ~(τ') }>⊢ T₁✝ = τ'
cases h' with
| ite _ _ _ _ _ _ h₂' _ => ite.ite Γ:Contexte:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝¹:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝¹:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>h₁_ih✝:∀ (τ' : Ty), <{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ') }> → <{ Bool }> = τ'ih₂:∀ (τ' : Ty), <{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ') }> → T₁✝ = τ'h₃_ih✝:∀ (τ' : Ty), <{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(τ') }> → T₁✝ = τ'τ':Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂':<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ') }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(τ') }>⊢ T₁✝ = τ'
apply ih₂ ite.ite Γ:Contexte:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:TmT₁✝:Tyh₁✝¹:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₁✝) }>h₃✝¹:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(T₁✝) }>h₁_ih✝:∀ (τ' : Ty), <{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ') }> → <{ Bool }> = τ'ih₂:∀ (τ' : Ty), <{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ') }> → T₁✝ = τ'h₃_ih✝:∀ (τ' : Ty), <{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(τ') }> → T₁✝ = τ'τ':Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Bool }>h₂':<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ') }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(τ') }>⊢ <{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ') }>
exact h₂' All goals completed! 🐙
6.6. Context Invariance (Optional)
Another standard technical lemma associated with typed languages
is context invariance. It states that typing is preserved under
"inessential changes" to the context Γ — in particular,
changes that do not affect any of the free variables of the
term. In this section, we establish this property for our system,
introducing some other standard terminology on the way.
First, we need to define the free variables in a term — i.e., variables that are used in the term in positions that are not in the scope of an enclosing function abstraction binding a variable of the same name.
More technically, a variable x appears free in a term t if
t contains some occurrence of x that is not under an
abstraction labeled x. For example:
-
yappears free, butxdoes not, inλx:τ → τ'. x y -
both
xandyappear free in(λx:τ → τ'. x y) x -
no variables appear free in
λx:τ → τ'. λy:τ. x y
We write this x ∈ᶠ t, reading the relation as "x is one of the free
variables of t". Formally:
section
set_option hygiene false in
local infix:50 " ∈ᶠ " => AppearsFreeIn
inductive AppearsFreeIn (x : String) : Tm → Prop where
| var : x ∈ᶠ (Tm.var x)
| app1 (t₁ t₂ : Tm) (h : x ∈ᶠ t₁) : x ∈ᶠ <{ ~t₁ ~t₂ }>
| app2 (t₁ t₂ : Tm) (h : x ∈ᶠ t₂) : x ∈ᶠ <{ ~t₁ ~t₂ }>
| abs (y : String) (τ₁ : Ty) (t₁ : Tm) (hne : y ≠ x) (h : x ∈ᶠ t₁) :
x ∈ᶠ <{ λ ~y : ~τ₁ . ~t₁ }>
| ite1 (t₁ t₂ t₃ : Tm) (h : x ∈ᶠ t₁) : x ∈ᶠ <{ if ~t₁ then ~t₂ else ~t₃ }>
| ite2 (t₁ t₂ t₃ : Tm) (h : x ∈ᶠ t₂) : x ∈ᶠ <{ if ~t₁ then ~t₂ else ~t₃ }>
| ite3 (t₁ t₂ t₃ : Tm) (h : x ∈ᶠ t₃) : x ∈ᶠ <{ if ~t₁ then ~t₂ else ~t₃ }>
end
scoped infix:50 " ∈ᶠ " => AppearsFreeIn
The free variables of a term are just the variables that appear free in it. This gives us another way to define closed terms — arguably a better one, since it applies even to ill-typed terms. Indeed, this is the standard definition of the term "closed."
def Tm.Closed (t : Tm) : Prop := ∀ x, ¬ x ∈ᶠ t
Conversely, an open term is one that may contain free variables. (I.e., every term is an open term; the closed terms are a subset of the open ones. "Open" precisely means "possibly containing free variables.")
(Officially optional, but strongly recommended!) In the space
below, write out the rules of the ∈ᶠ relation in
informal inference-rule notation. (Use whatever notational
conventions you like — the point of the exercise is just for you
to think a bit about the meaning of each rule.) Although this is
a rather low-level, technical definition, understanding it is
crucial to understanding substitution and its properties, which
are really the crux of the lambda-calculus.
LATER: Fill in an official solution (no solution yet)
Next, we show that if a variable x appears free in a term t,
and if we know t is well typed in context Γ, then it
must be the case that Γ assigns a type to x.
Proof: We show, by induction on the proof that x appears free
in t, that, for all contexts Γ, if t is well typed under
Γ, then Γ assigns some type to x.
-
If the last rule used is
AppearsFreeIn.var, thent = x, and from the assumption thattis well typed underΓwe have immediately thatΓassigns a type tox. -
If the last rule used is
AppearsFreeIn.app1, thent = t₁ t₂andxappears free int₁. Sincetis well typed underΓ, we can see from the typing rules thatt₁must also be, and the IH then tells us thatΓassignsxa type. -
Almost all the other cases are similar:
xappears free in a subterm oft, and sincetis well typed underΓ, we know the subterm oftin whichxappears is well typed underΓas well, and the IH gives us exactly the conclusion we want. -
The only remaining case is
AppearsFreeIn.abs. In this caset = λy:τ₁. t₁andxappears free int₁, and we also know thatxis different fromy. The difference from the previous cases is that, whereastis well typed underΓ, its bodyt₁is well typed undery ↦ τ₁ ; Γ, so the IH allows us to conclude thatxis assigned some type by the extended contexty ↦ τ₁ ; Γ. To conclude thatΓassigns a type tox, we appeal to lemmaPartialMap.update_neq, noting thatxandyare different variables.
Complete the following proof.
theorem free_in_context (x : String) (t : Tm) (τ : Ty) (Γ : Context)
(ha : x ∈ᶠ t) (hτ : <{ ~Γ ⊢ ~t ⦂ ~τ }>) : ∃ τ', Γ[x] = some τ' := by x:Stringt:Tmτ:TyΓ:Contextha:x ∈ᶠ thτ:<{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ'
induction ha generalizing Γ τ with
| var => var x:Stringt:Tmτ:TyΓ:Contexthτ:<{ ~(Γ) ⊢ ~(Stlc.Tm.var x) ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ'
cases hτ with
| var _ _ _ h => var.var x:Stringt:Tmτ:TyΓ:Contexth:Γ[x] = some τ⊢ ∃ τ', Γ[x] = some τ'
constructor var.var.h x:Stringt:Tmτ:TyΓ:Contexth:Γ[x] = some τ⊢ Γ[x] = some ?var.var.wvar.var.w x:Stringt:Tmτ:TyΓ:Contexth:Γ[x] = some τ⊢ Ty
exact h All goals completed! 🐙
| app1 _ _ _ ih => app1 x:Stringt:Tmt₁✝:Tmt₂✝:Tmh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexthτ:<{ ~(Γ) ⊢ t₁✝ t₂✝ ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ'
cases hτ with
| app _ _ _ _ _ h₁ _ => app1.app x:Stringt:Tmt₁✝:Tmt₂✝:Tmh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:ContextT₂✝:Tyh₂✝:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>h₁:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ T₂✝ → τ }>⊢ ∃ τ', Γ[x] = some τ'
apply ih app1.app.hτ x:Stringt:Tmt₁✝:Tmt₂✝:Tmh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:ContextT₂✝:Tyh₂✝:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>h₁:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ T₂✝ → τ }>⊢ <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(?app1.app.τ) }>app1.app.τ x:Stringt:Tmt₁✝:Tmt₂✝:Tmh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:ContextT₂✝:Tyh₂✝:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>h₁:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ T₂✝ → τ }>⊢ Ty
exact h₁ All goals completed! 🐙
| app2 _ _ _ ih => app2 x:Stringt:Tmt₁✝:Tmt₂✝:Tmh✝:x ∈ᶠ t₂✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexthτ:<{ ~(Γ) ⊢ t₁✝ t₂✝ ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ'
cases hτ with
| app _ _ _ _ _ _ h₂ => app2.app x:Stringt:Tmt₁✝:Tmt₂✝:Tmh✝:x ∈ᶠ t₂✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:ContextT₂✝:Tyh₂:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>h₁✝:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ T₂✝ → τ }>⊢ ∃ τ', Γ[x] = some τ'
apply ih app2.app.hτ x:Stringt:Tmt₁✝:Tmt₂✝:Tmh✝:x ∈ᶠ t₂✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:ContextT₂✝:Tyh₂:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>h₁✝:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ T₂✝ → τ }>⊢ <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(?app2.app.τ) }>app2.app.τ x:Stringt:Tmt₁✝:Tmt₂✝:Tmh✝:x ∈ᶠ t₂✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:ContextT₂✝:Tyh₂:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>h₁✝:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ T₂✝ → τ }>⊢ Ty
exact h₂ All goals completed! 🐙
| abs y _ _ hne _ ih => abs x:Stringt:Tmy:Stringτ₁✝:Tyt₁✝:Tmhne:y ≠ xh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexthτ:<{ ~(Γ) ⊢ λ ~y : τ₁✝ . t₁✝ ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ'
solution!
cases hτ with
| abs _ _ _ _ _ hb => abs.abs x:Stringt:Tmy:Stringτ₁✝:Tyt₁✝:Tmhne:y ≠ xh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'Γ:ContextT₁✝:Tyhb:<{ ~(y →ₚ τ₁✝ ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>⊢ ∃ τ', Γ[x] = some τ'
obtain ⟨τ', h⟩ := ih _ _ hb abs.abs x:Stringt:Tmy:Stringτ₁✝:Tyt₁✝:Tmhne:y ≠ xh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'Γ:ContextT₁✝:Tyhb:<{ ~(y →ₚ τ₁✝ ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>τ':Tyh:(y →ₚ τ₁✝ ; Γ)[x] = some τ'⊢ ∃ τ', Γ[x] = some τ'
rw [PartialMap.update_neq hne abs.abs x:Stringt:Tmy:Stringτ₁✝:Tyt₁✝:Tmhne:y ≠ xh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'Γ:ContextT₁✝:Tyhb:<{ ~(y →ₚ τ₁✝ ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>τ':Tyh:Γ[x] = some τ'⊢ ∃ τ', Γ[x] = some τ'] at h abs.abs x:Stringt:Tmy:Stringτ₁✝:Tyt₁✝:Tmhne:y ≠ xh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'Γ:ContextT₁✝:Tyhb:<{ ~(y →ₚ τ₁✝ ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>τ':Tyh:Γ[x] = some τ'⊢ ∃ τ', Γ[x] = some τ'
exists τ' All goals completed! 🐙
| ite1 _ _ _ _ ih => ite1 x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexthτ:<{ ~(Γ) ⊢ if t₁✝ then t₂✝ else t₃✝ ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ'
cases hτ with
| ite _ _ _ _ _ h₁ _ _ => ite1.ite x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexth₁:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }>h₃✝:<{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ'
apply ih ite1.ite.hτ x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexth₁:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }>h₃✝:<{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(?ite1.ite.τ) }>ite1.ite.τ x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexth₁:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }>h₃✝:<{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }>⊢ Ty
exact h₁ All goals completed! 🐙
| ite2 _ _ _ _ ih => ite2 x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₂✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexthτ:<{ ~(Γ) ⊢ if t₁✝ then t₂✝ else t₃✝ ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ'
cases hτ with
| ite _ _ _ _ _ _ h₂ _ => ite2.ite x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₂✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexth₁✝:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ Bool }>h₂:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }>h₃✝:<{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ'
apply ih ite2.ite.hτ x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₂✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexth₁✝:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ Bool }>h₂:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }>h₃✝:<{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(?ite2.ite.τ) }>ite2.ite.τ x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₂✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexth₁✝:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ Bool }>h₂:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }>h₃✝:<{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }>⊢ Ty
exact h₂ All goals completed! 🐙
| ite3 _ _ _ _ ih => ite3 x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₃✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexthτ:<{ ~(Γ) ⊢ if t₁✝ then t₂✝ else t₃✝ ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ'
cases hτ with
| ite _ _ _ _ _ _ _ h₃ => ite3.ite x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₃✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexth₁✝:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }>h₃:<{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ'
apply ih ite3.ite.hτ x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₃✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexth₁✝:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }>h₃:<{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(?ite3.ite.τ) }>ite3.ite.τ x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₃✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexth₁✝:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }>h₃:<{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }>⊢ Ty
exact h₃ All goals completed! 🐙
From the free_in_context lemma, it immediately follows that any
term t that is well typed in the empty context is closed (it has
no free variables).
theorem typable_empty_closed (t : Tm) (τ : Ty) (hτ : <{ ∅ ⊢ ~t ⦂ ~τ }>) : t.Closed := by t:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ t.Closed
solution!
intro x ha t:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>x:Stringha:x ∈ᶠ t⊢ False
obtain ⟨τ', hc⟩ := free_in_context x t τ ∅ ha hτ t:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>x:Stringha:x ∈ᶠ tτ':Tyhc:∅[x] = some τ'⊢ False
rw [PartialMap.getElem_empty t:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>x:Stringha:x ∈ᶠ tτ':Tyhc:none = some τ'⊢ False] at hc t:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>x:Stringha:x ∈ᶠ tτ':Tyhc:none = some τ'⊢ False
cases hc All goals completed! 🐙
Finally, we establish context invariance. It is useful in cases
when we have a proof of some typing relation Γ ⊢ t ⦂ τ,
and we need to replace Γ by a different context Γ'.
When is it safe to do this? Intuitively, it must at least be the
case that Γ' assigns the same types as Γ to all the
variables that appear free in t. In fact, this is the only
condition that is needed.
Proof: By induction on the derivation of Γ ⊢ t ⦂ τ.
-
If the last rule in the derivation was
HasType.var, thent = xandΓ x = τ. By assumption,Γ' x = τas well, and henceΓ' ⊢ t ⦂ τbyHasType.var. -
If the last rule was
HasType.abs, thent = λy:τ₂. t₁, withτ = τ₂ → τ₁andy ↦ τ₂ ; Γ ⊢ t₁ ⦂ τ₁. The induction hypothesis states that for any contextΓ'', ify ↦ τ₂ ; ΓandΓ''assign the same types to all the free variables int₁, thent₁has typeτ₁underΓ''. LetΓ'be a context which agrees withΓon the free variables int; we must showΓ' ⊢ λy:τ₂. t₁ ⦂ τ₂ → τ₁.By
HasType.abs, it suffices to show thaty ↦ τ₂ ; Γ' ⊢ t₁ ⦂ τ₁. By the IH (settingΓ'' = y ↦ τ₂ ; Γ'), it suffices to show thaty ↦ τ₂ ; Γandy ↦ τ₂ ; Γ'agree on all the variables that appear free int₁.Any variable occurring free in
t₁must be eitheryor some other variable.y ↦ τ₂ ; Γandy ↦ τ₂ ; Γ'clearly agree ony. Otherwise, note that any variable other thanythat occurs free int₁also occurs free int = λy:τ₂. t₁, and by assumptionΓandΓ'agree on all such variables; hence so doy ↦ τ₂ ; Γandy ↦ τ₂ ; Γ'. -
If the last rule was
HasType.app, thent = t₁ t₂, withΓ ⊢ t₁ ⦂ τ₂ → τandΓ ⊢ t₂ ⦂ τ₂. One induction hypothesis states that for all contextsΓ', ifΓ'agrees withΓon the free variables int₁, thent₁has typeτ₂ → τunderΓ'; there is a similar IH fort₂. We must show thatt₁ t₂also has typeτunderΓ', given the assumption thatΓ'agrees withΓon all the free variables int₁ t₂. ByHasType.app, it suffices to show thatt₁andt₂each have the same type underΓ'as underΓ. But all free variables int₁are also free int₁ t₂, and similarly fort₂; hence the desired result follows from the induction hypotheses.
Complete the following proof.
theorem context_invariance (Γ Γ' : Context) (t : Tm) (τ : Ty)
(hτ : <{ ~Γ ⊢ ~t ⦂ ~τ }>) (hf : ∀ x, x ∈ᶠ t → Γ[x] = Γ'[x]) :
<{ ~Γ' ⊢ ~t ⦂ ~τ }> := by Γ:ContextΓ':Contextt:Tmτ:Tyhτ:<{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>hf:∀ (x : String), x ∈ᶠ t → Γ[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ ~(t) ⦂ ~(τ) }>
induction hτ generalizing Γ' with
| var _ x _ h => var Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:Tyh:Γ✝[x] = some T₁✝Γ':Contexthf:∀ (x_1 : String), x_1 ∈ᶠ Stlc.Tm.var x → Γ✝[x_1] = Γ'[x_1]⊢ <{ ~(Γ') ⊢ ~(Stlc.Tm.var x) ⦂ ~(T₁✝) }>
solution!
constructor var Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:Tyh:Γ✝[x] = some T₁✝Γ':Contexthf:∀ (x_1 : String), x_1 ∈ᶠ Stlc.Tm.var x → Γ✝[x_1] = Γ'[x_1]⊢ Γ'[x] = some T₁✝
rw [← h var Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:Tyh:Γ✝[x] = some T₁✝Γ':Contexthf:∀ (x_1 : String), x_1 ∈ᶠ Stlc.Tm.var x → Γ✝[x_1] = Γ'[x_1]⊢ Γ'[x] = Γ✝[x]] var Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:Tyh:Γ✝[x] = some T₁✝Γ':Contexthf:∀ (x_1 : String), x_1 ∈ᶠ Stlc.Tm.var x → Γ✝[x_1] = Γ'[x_1]⊢ Γ'[x] = Γ✝[x]
symm var Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:Tyh:Γ✝[x] = some T₁✝Γ':Contexthf:∀ (x_1 : String), x_1 ∈ᶠ Stlc.Tm.var x → Γ✝[x_1] = Γ'[x_1]⊢ Γ✝[x] = Γ'[x]
apply hf var Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:Tyh:Γ✝[x] = some T₁✝Γ':Contexthf:∀ (x_1 : String), x_1 ∈ᶠ Stlc.Tm.var x → Γ✝[x_1] = Γ'[x_1]⊢ x ∈ᶠ Stlc.Tm.var x
constructor All goals completed! 🐙
| abs _ y _ _ _ _ ih => abs Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ λ ~y : T₂✝ . t₁✝ ⦂ T₂✝ → T₁✝ }>
solution!
constructor abs Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]⊢ <{ ~(y →ₚ T₂✝ ; Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>
apply ih abs Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]⊢ ∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = (y →ₚ T₂✝ ; Γ')[x]
intro z hz abs Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁✝⊢ (y →ₚ T₂✝ ; Γ✝)[z] = (y →ₚ T₂✝ ; Γ')[z]
by_cases hyz : y = z pos Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁✝hyz:y = z⊢ (y →ₚ T₂✝ ; Γ✝)[z] = (y →ₚ T₂✝ ; Γ')[z]neg Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁✝hyz:¬y = z⊢ (y →ₚ T₂✝ ; Γ✝)[z] = (y →ₚ T₂✝ ; Γ')[z]
· pos Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁✝hyz:y = z⊢ (y →ₚ T₂✝ ; Γ✝)[z] = (y →ₚ T₂✝ ; Γ')[z] subst hyz pos Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]hz:y ∈ᶠ t₁✝⊢ (y →ₚ T₂✝ ; Γ✝)[y] = (y →ₚ T₂✝ ; Γ')[y]; rw [PartialMap.update_eq, pos Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]hz:y ∈ᶠ t₁✝⊢ some T₂✝ = (y →ₚ T₂✝ ; Γ')[y] PartialMap.update_eq pos Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]hz:y ∈ᶠ t₁✝⊢ some T₂✝ = some T₂✝] All goals completed! 🐙
-- The only tricky step.
· neg Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁✝hyz:¬y = z⊢ (y →ₚ T₂✝ ; Γ✝)[z] = (y →ₚ T₂✝ ; Γ')[z] rw [PartialMap.update_neq hyz, neg Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁✝hyz:¬y = z⊢ Γ✝[z] = (y →ₚ T₂✝ ; Γ')[z] PartialMap.update_neq hyz neg Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁✝hyz:¬y = z⊢ Γ✝[z] = Γ'[z]] neg Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁✝hyz:¬y = z⊢ Γ✝[z] = Γ'[z]
apply hf neg Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁✝hyz:¬y = z⊢ z ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }>
apply AppearsFreeIn.abs neg.hne Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁✝hyz:¬y = z⊢ y ≠ zneg.h Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁✝hyz:¬y = z⊢ z ∈ᶠ t₁✝ <;> neg.hne Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁✝hyz:¬y = z⊢ y ≠ zneg.h Γ:Contextt:Tmτ:TyΓ✝:Contexty:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(y →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁✝ → (y →ₚ T₂✝ ; Γ✝)[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ λ ~y : T₂✝ . t₁✝ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁✝hyz:¬y = z⊢ z ∈ᶠ t₁✝ assumption All goals completed! 🐙
| app _ _ _ t₁ t₂ _ _ ih₁ ih₂ => app Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁:Tmt₂:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₂✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₂✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ t₁ t₂ }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ t₁ t₂ ⦂ ~(T₁✝) }>
solution!
constructor app.h₁ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁:Tmt₂:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₂✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₂✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ t₁ t₂ }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ ~(t₁) ⦂ ~?app.T₂ → T₁✝ }>app.h₂ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁:Tmt₂:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₂✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₂✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ t₁ t₂ }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(?app.T₂) }>app.T₂ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁:Tmt₂:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₂✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₂✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ t₁ t₂ }> → Γ✝[x] = Γ'[x]⊢ Ty
· app.h₁ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁:Tmt₂:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₂✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₂✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ t₁ t₂ }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ ~(t₁) ⦂ ~?app.T₂ → T₁✝ }> apply ih₁ app.h₁ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁:Tmt₂:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₂✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₂✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ t₁ t₂ }> → Γ✝[x] = Γ'[x]⊢ ∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]
intro z hz app.h₁ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁:Tmt₂:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₂✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₂✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ t₁ t₂ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁⊢ Γ✝[z] = Γ'[z]
apply hf app.h₁ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁:Tmt₂:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₂✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₂✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ t₁ t₂ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁⊢ z ∈ᶠ <{ t₁ t₂ }>
apply AppearsFreeIn.app1 app.h₁ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁:Tmt₂:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₂✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₂✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ t₁ t₂ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁⊢ z ∈ᶠ t₁
exact hz All goals completed! 🐙
· app.h₂ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁:Tmt₂:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₂✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₂✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ t₁ t₂ }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₂✝) }> apply ih₂ app.h₂ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁:Tmt₂:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₂✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₂✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ t₁ t₂ }> → Γ✝[x] = Γ'[x]⊢ ∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]
intro z hz app.h₂ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁:Tmt₂:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₂✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₂✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ t₁ t₂ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₂⊢ Γ✝[z] = Γ'[z]
apply hf app.h₂ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁:Tmt₂:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₂✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₂✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ t₁ t₂ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₂⊢ z ∈ᶠ <{ t₁ t₂ }>
apply AppearsFreeIn.app2 app.h₂ Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁:Tmt₂:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₂✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ T₂✝ → T₁✝ }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₂✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ t₁ t₂ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₂⊢ z ∈ᶠ t₂
exact hz All goals completed! 🐙
| tru => tru Γ:Contextt:Tmτ:TyΓ✝:ContextΓ':Contexthf:∀ (x : String), x ∈ᶠ <{ true }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ true ⦂ Bool }> constructor All goals completed! 🐙
| fls => fls Γ:Contextt:Tmτ:TyΓ✝:ContextΓ':Contexthf:∀ (x : String), x ∈ᶠ <{ false }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ false ⦂ Bool }> constructor All goals completed! 🐙
| ite _ t₁ t₂ t₃ _ _ _ _ ih₁ ih₂ ih₃ => ite Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ if t₁ then t₂ else t₃ ⦂ ~(T₁✝) }>
constructor ite.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ite.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ite.h₃ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>
· ite.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }> apply ih₁ ite.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]⊢ ∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]
intro z hz ite.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁⊢ Γ✝[z] = Γ'[z]
apply hf ite.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁⊢ z ∈ᶠ <{ if t₁ then t₂ else t₃ }>
apply AppearsFreeIn.ite1 ite.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₁⊢ z ∈ᶠ t₁
exact hz All goals completed! 🐙
· ite.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }> apply ih₂ ite.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]⊢ ∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]
intro z hz ite.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₂⊢ Γ✝[z] = Γ'[z]
apply hf ite.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₂⊢ z ∈ᶠ <{ if t₁ then t₂ else t₃ }>
apply AppearsFreeIn.ite2 ite.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₂⊢ z ∈ᶠ t₂
exact hz All goals completed! 🐙
· ite.h₃ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }> apply ih₃ ite.h₃ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]⊢ ∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]
intro z hz ite.h₃ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₃⊢ Γ✝[z] = Γ'[z]
apply hf ite.h₃ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₃⊢ z ∈ᶠ <{ if t₁ then t₂ else t₃ }>
apply AppearsFreeIn.ite3 ite.h₃ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁:Tmt₂:Tmt₃:TmT₁✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁) ⦂ Bool }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂) ⦂ ~(T₁✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃) ⦂ ~(T₁✝) }>ih₁:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₁ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₁) ⦂ Bool }>ih₂:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₂ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₂) ⦂ ~(T₁✝) }>ih₃:∀ (Γ' : Context), (∀ (x : String), x ∈ᶠ t₃ → Γ✝[x] = Γ'[x]) → <{ ~(Γ') ⊢ ~(t₃) ⦂ ~(T₁✝) }>Γ':Contexthf:∀ (x : String), x ∈ᶠ <{ if t₁ then t₂ else t₃ }> → Γ✝[x] = Γ'[x]z:Stringhz:z ∈ᶠ t₃⊢ z ∈ᶠ t₃
exact hz All goals completed! 🐙
The context invariance lemma can actually be used in place of the weakening lemma to prove the crucial substitution lemma stated earlier.
6.7. Additional Exercises
(Officially optional, but strongly recommended!) Without peeking
at their statements above, write down the progress and
preservation theorems for the simply typed lambda-calculus (as Lean
theorems). You can write sorry for the proofs.
At least one person was confused by what to name these. We could simplify life by giving the names explicitly and just omitting the bodies. Indeed, once we do that we could autograde this by demanding that what they write be identical to what we wrote above! Maybe a better way to solve this would be to have the following template. BCP 21: Yes, do this!!
theorem progress_statement :
FILL IN HERE := by
apply progress
theorem preservation_statement :
FILL IN HERE := by
apply preservation
See progress and preservation above. Their statements are:
theorem progress_statement (t : Tm) (τ : Ty) (hτ : <{ ∅ ⊢ ~t ⦂ ~τ }>) :
t.IsValue ∨ ∃ t', t ⟶ t' := by
sorry
theorem preservation_statement (t t' : Tm) (τ : Ty)
(hτ : <{ ∅ ⊢ ~t ⦂ ~τ }>) (hs : t ⟶ t') : <{ ∅ ⊢ ~t' ⦂ ~τ }> := by
sorry
Suppose we add a new term zap with the following reduction rule
--------- (zap)
t ⟶ zap
and the following typing rule:
----------- (zap)
Γ ⊢ zap ⦂ τ
Which of the following properties of the STLC remain true in the presence of these rules? For each property, write either "remains true" or "becomes false." If a property becomes false, give a counterexample.
-
Determinism of
Step
Becomes false. For instance (if true then false else true) ⟶ false
and (if true then false else true) ⟶ zap.
-
Progress
Remains true. Every term (including zap) can take a step to zap.
-
Preservation
Remains true. zap can have any type.
Suppose instead that we add a new term foo with the following
reduction rules:
----------------- (foo1)
(λx:τ. x) ⟶ foo
------------ (foo2)
foo ⟶ true
Which of the following properties of the STLC remain true in the presence of this rule? For each one, write either "remains true" or else "becomes false." If a property becomes false, give a counterexample.
-
Determinism of
Step
Becomes false. The term (λx:Bool. x) true might step
to either true by the rule Step.appAbs or
to foo true by the rules Step.app1 and Step.foo1.
-
Progress
Remains true. We are only adding to the step relation, and this can never damage progress.
-
Preservation
Becomes false. For example,
∅ ⊢ λx:Bool. x ⦂ Bool → Bool and (λx:Bool. x) ⟶ foo by Step.foo1,
but, since we have no typing rules for foo, we cannot prove that
∅ ⊢ foo ⦂ Bool → Bool.
Suppose instead that we remove the rule Step.app1 from the Step
relation. Which of the following properties of the STLC remain
true in the presence of this rule? For each one, write either
"remains true" or else "becomes false." If a property becomes
false, give a counterexample.
-
Determinism of
Step
Remains true. Removing reduction rules can only make Step
more deterministic.
-
Progress
Becomes false. For example,
((λx:Bool → Bool. λy:Bool → Bool. x) (λz:Bool. z)) (λz:Bool. z)
is well typed, but stuck.
-
Preservation
Remains true. Removing reduction rules can't break preservation.
Suppose instead that we add the following new rule to the reduction relation:
---------------------------------- (funnyIfTrue)
(if true then t₁ else t₂) ⟶ true
Which of the following properties of the STLC remain true in the presence of this rule? For each one, write either "remains true" or else "becomes false." If a property becomes false, give a counterexample.
-
Determinism of
Step
Becomes false, for instance:
(if true then false else false) ⟶ false and
(if true then false else false) ⟶ true
-
Progress
Remains true. We are only adding to the step relation, and this can never damage progress.
-
Preservation
Becomes false. For example,
∅ ⊢ if true then (λx:Bool. x) else (λx:Bool. x) ⦂ Bool → Bool
and (if true then (λx:Bool. x) else (λx:Bool. x)) ⟶ true
but it's not the case that ∅ ⊢ true ⦂ Bool → Bool.
Suppose instead that we add the following new rule to the typing relation:
Γ ⊢ t₁ ⦂ Bool → Bool → Bool
Γ ⊢ t₂ ⦂ Bool
------------------------------ (funnyApp)
Γ ⊢ t₁ t₂ ⦂ Bool
Which of the following properties of the STLC remain true in the presence of this rule? For each one, write either "remains true" or else "becomes false." If a property becomes false, give a counterexample.
-
Determinism of
Step
Remains true. We are only adding to the typing relation, and
this can never damage determinism of Step.
-
Progress
Remains true. Since the new rule still requires that t₁ is
a function we can still apply Step.appAbs to show progress.
-
Preservation
Becomes false. For example,
∅ ⊢ (λx:Bool. λy:Bool. x) true ⦂ Bool
and (λx:Bool. λy:Bool. x) true ⟶ λy:Bool. true
but it's not the case that ∅ ⊢ λy:Bool. true ⦂ Bool
Suppose instead that we add the following new rule to the typing relation:
Γ ⊢ t₁ ⦂ Bool
Γ ⊢ t₂ ⦂ Bool
------------------ (funnyApp')
Γ ⊢ t₁ t₂ ⦂ Bool
Which of the following properties of the STLC remain true in the presence of this rule? For each one, write either "remains true" or else "becomes false." If a property becomes false, give a counterexample.
-
Determinism of
Step
Remains true. We are not changing the Step relation.
-
Progress
Becomes false. For instance, true true is a term that
becomes typable (at type Bool), but which is stuck.
-
Preservation
Remains true. There are 3 ways t₁ t₂ can reduce. For
Step.app1 and Step.app2 we can still apply the induction
hypothesis. To reduce t₁ t₂ using Step.appAbs
t₁ would need to be a function, but functions don't have
type Bool.
Suppose we add the following new rule to the typing relation of the STLC:
------------------------ (funnyAbs)
∅ ⊢ λx:Bool. t ⦂ Bool
Which of the following properties of the STLC remain true in the presence of this rule? For each one, write either "remains true" or else "becomes false." If a property becomes false, give a counterexample.
-
Determinism of
Step
Remains true. We're not changing the Step relation.
-
Progress
Becomes false. For instance if (λx:Bool. false) then false else false
is a term that would become typable, although it is stuck.
-
Preservation
Remains true. λx:Bool. t doesn't step.
The STLC typing relation with the funnyAbs rule of stlc_variation7 added,
and a proof that progress then fails.
end Stlc
6.7.1. Exercise: STLC with Arithmetic
To see how the STLC might function as the core of a real programming language, let's extend it with a concrete base type of numbers and some constants and primitive operators.
The arithmetic we are adding is the arithmetic of the Slang chapter — numeric constants and multiplication — together with the successor, predecessor, and zero-test operations of the Types chapter. What is new is the setting: those operations now live in a language that also has variables, abstraction, and application, so an arithmetic computation can be packaged up as a function and passed around as a value.
namespace StlcArith
open scoped MyGetElem
To types, we add a base type of natural numbers (and remove booleans, for brevity).
inductive Ty where
| arrow (τ₁ τ₂ : Ty)
| nat
To terms, we add natural number constants, along with successor, predecessor, multiplication, and zero-testing.
inductive Tm where
| var (x : String)
| app (t₁ t₂ : Tm)
| abs (x : String) (τ : Ty) (t : Tm)
| const (n : Nat)
| succ (t : Tm)
| pred (t : Tm)
| mult (t₁ t₂ : Tm)
| ite0 (c t e : Tm)
StlcArith is a different language from the STLC of this chapter, not an
extension of it, so it needs its own concrete syntax. Rather than invent a new
one, we reuse the grammars set up in the Stlc chapter — the
syntax categories stlcTy, stlcTm, and stlcVar — and give them a new
meaning here. Terms and types of this language are therefore written inside
the same <{ … }> brackets, with the same ~e escape back to Lean.
Notation encoding: types
The type grammar needs no new productions: Nat is a bare identifier, which
the template already accepts, and arrows and parentheses are unchanged. Only
the macro_rules are new, and they differ from the STLC's in just two places
— the identifier Nat names this language's base type, and the arrow builds
this language's StlcArith.Ty.arrow.
scoped macro_rules (kind := Stlc.tyBracket)
| `(<{ ~$τ:term }>) => pure τ
| `(<{ ($τ:stlcTy) }>) => `(<{ $τ:stlcTy }>)
| `(<{ $x:ident }>) =>
match x.getId.toString with
| "Nat" => `(Ty.nat)
| _ => `(($x : Ty))
| `(<{ $τ₁:stlcTy → $τ₂:stlcTy }>) => `(Ty.arrow <{ $τ₁:stlcTy }> <{ $τ₂:stlcTy }>)
| `(<{ $τ₁:stlcTy -> $τ₂:stlcTy }>) => `(Ty.arrow <{ $τ₁:stlcTy }> <{ $τ₂:stlcTy }>)
Notation encoding: terms
Terms do need new productions: a numeral, an infix *, and the zero test.
Multiplication binds looser than application and tighter than λ, so x * y z
multiplies x by the application y z; it associates to the right, so
x * y * z is x * (y * z).
succ and pred get no production of their own. Making them keywords would
reserve those words globally — and we would then be unable to write succ as
a case name in a proof, including for Lean's own Nat. Instead they are
written as though they were functions applied to an argument, succ t, and the
application rule below recognizes them. if0 is a keyword, since then and
else leave no other option; that is why the constructor above is called
StlcArith.Tm.ite0 rather than if0, just as the STLC's conditional is
Stlc.Tm.ite.
scoped syntax:max num : stlcTm
scoped syntax:60 stlcTm:61 " * " stlcTm:60 : stlcTm
scoped syntax:50 "if0 " stlcTm:51 " then " stlcTm:50 " else " stlcTm:50 : stlcTm
open Lean in
scoped macro_rules (kind := Stlc.tmBracket)
| `(<{ ~$e:term }>) => pure e
| `(<{ ($t:stlcTm) }>) => `(<{ $t:stlcTm }>)
| `(<{ $n:num }>) => `(Tm.const $n)
| `(<{ $x:ident }>) =>
match x.getId.toString with
| "Nat" => Macro.throwErrorAt x "`Nat` is a type, not a term"
| "succ" => Macro.throwErrorAt x "`succ` must be applied to an argument"
| "pred" => Macro.throwErrorAt x "`pred` must be applied to an argument"
| _ => `(Tm.var $(quote x.getId.toString))
| `(<{ $t₁:stlcTm $t₂:stlcTm }>) =>
match t₁ with
| `(stlcTm| $f:ident) =>
match f.getId.toString with
| "succ" => `(Tm.succ <{ $t₂:stlcTm }>)
| "pred" => `(Tm.pred <{ $t₂:stlcTm }>)
| _ => `(Tm.app <{ $t₁:stlcTm }> <{ $t₂:stlcTm }>)
| _ => `(Tm.app <{ $t₁:stlcTm }> <{ $t₂:stlcTm }>)
| `(<{ λ $x : $τ . $t }>) => do
`(Tm.abs $(← Stlc.varStr x) <{ $τ:stlcTy }> <{ $t:stlcTm }>)
| `(<{ $t₁:stlcTm * $t₂:stlcTm }>) => `(Tm.mult <{ $t₁:stlcTm }> <{ $t₂:stlcTm }>)
| `(<{ if0 $c then $t else $e }>) =>
`(Tm.ite0 <{ $c:stlcTm }> <{ $t:stlcTm }> <{ $e:stlcTm }>)
Notation encoding: printing it back
As in the Stlc chapter, a delaborator runs the grammar backwards, so that goals mentioning these terms and types read in the concrete syntax. The parenthesizers registered there are for the whole syntax category, so they serve this language too and are not repeated.
open Lean in
/-- Is `s` usable as a bare variable in `stlcTm` rather than as reserved syntax? -/
def isPlainTmVarName (s : String) : Bool :=
Stlc.isPlainName s && s != "Nat" && s != "succ" && s != "pred"
open Lean PrettyPrinter Delaborator SubExpr in
/-- Rebuild `stlcTy` concrete syntax from a `Ty` value. -/
partial def delabTyInner : DelabM (TSyntax `stlcTy) := do
let stx ←
match_expr ← getExpr with
| Ty.nat => `(stlcTy| $(mkIdent `Nat):ident)
| Ty.arrow _ _ => do
let a ← withAppFn <| withAppArg delabTyInner
let b ← withAppArg delabTyInner
`(stlcTy| $a → $b)
| _ => do
match ← delab with
| `($i:ident) => `(stlcTy| $i:ident)
| e => `(stlcTy| ~$e)
(⟨·⟩) <$> annotateTermInfo ⟨stx.raw⟩
open Lean PrettyPrinter Delaborator SubExpr in
/-- Rebuild `stlcTm` concrete syntax from a `Tm` value. -/
partial def delabTmInner : DelabM (TSyntax `stlcTm) := do
let stx ←
match_expr ← getExpr with
| Tm.var _ => do
let x ← withAppArg delab
match x with
| `($s:str) =>
if isPlainTmVarName s.getString then
`(stlcTm| $(mkIdent (Name.mkSimple s.getString)):ident)
else
let var : Term := mkIdent ``StlcArith.Tm.var
`(stlcTm| ~($var $x))
| _ =>
let var : Term := mkIdent ``StlcArith.Tm.var
`(stlcTm| ~($var $x))
| Tm.const _ => do
let n ← withAppArg delab
match n with
| `($n:num) => `(stlcTm| $n:num)
| _ =>
let const : Term := mkIdent ``StlcArith.Tm.const
`(stlcTm| ~($const $n))
| Tm.app _ _ => do
let f ← withAppFn <| withAppArg delabTmInner
let a ← withAppArg delabTmInner
`(stlcTm| $f $a)
| Tm.abs _ _ _ => do
let x ← withAppFn <| withAppFn <| withAppArg Stlc.delabVarInner
let τ ← withAppFn <| withAppArg delabTyInner
let t ← withAppArg delabTmInner
`(stlcTm| λ $x : $τ . $t)
| Tm.succ _ => do
let t ← withAppArg delabTmInner
`(stlcTm| $(mkIdent `succ):ident $t)
| Tm.pred _ => do
let t ← withAppArg delabTmInner
`(stlcTm| $(mkIdent `pred):ident $t)
| Tm.mult _ _ => do
let a ← withAppFn <| withAppArg delabTmInner
let b ← withAppArg delabTmInner
`(stlcTm| $a * $b)
| Tm.ite0 _ _ _ => do
let c ← withAppFn <| withAppFn <| withAppArg delabTmInner
let t ← withAppFn <| withAppArg delabTmInner
let e ← withAppArg delabTmInner
`(stlcTm| if0 $c then $t else $e)
| _ => do
-- `subst` is defined below, so it is matched by name rather than with
-- `match_expr`; a substitution prints in its own bracket notation.
let e ← getExpr
if e.getAppFn.constName? == some `StlcArith.subst && e.getAppNumArgs == 3 then
let x ← withAppFn <| withAppFn <| withAppArg Stlc.delabVarInner
let s ← withAppFn <| withAppArg delabTmInner
let t ← withAppArg delabTmInner
`(stlcTm| [$x := $s] $t)
else
match ← delab with
| `($i:ident) => `(stlcTm| $i:ident)
| e => `(stlcTm| ~$e)
(⟨·⟩) <$> annotateTermInfo ⟨stx.raw⟩
open Lean PrettyPrinter Delaborator SubExpr in
@[delab app.StlcArith.Ty.nat, delab app.StlcArith.Ty.arrow]
def delabTy : Delab := whenPPOption getPPNotation do
guard <| match_expr ← getExpr with
| Ty.nat => true | Ty.arrow _ _ => true | _ => false
match ← delabTyInner with
| `(stlcTy| ~$e) => pure e
| e => `(<{ $e:stlcTy }>)
open Lean PrettyPrinter Delaborator SubExpr in
@[delab app.StlcArith.Tm.var, delab app.StlcArith.Tm.app, delab app.StlcArith.Tm.abs,
delab app.StlcArith.Tm.const, delab app.StlcArith.Tm.succ, delab app.StlcArith.Tm.pred,
delab app.StlcArith.Tm.mult, delab app.StlcArith.Tm.ite0]
def delabTm : Delab := whenPPOption getPPNotation do
guard <| match_expr ← getExpr with
| Tm.var _ => true | Tm.app _ _ => true | Tm.abs _ _ _ => true
| Tm.const _ => true | Tm.succ _ => true | Tm.pred _ => true
| Tm.mult _ _ => true | Tm.ite0 _ _ _ => true
| _ => false
match ← delabTmInner with
| `(stlcTm| ~($e)) => pure e
| `(stlcTm| ~$e) => pure e
| e => `(<{ $e:stlcTm }>)
Checks that the extended grammar parses the way it should.
In this extended exercise, your job is to finish formalizing the definition and properties of the STLC extended with arithmetic. Specifically:
Fill in the core definitions for StlcArith, by starting with the rules
and terms which are the same as the STLC. Then prove the key lemmas and
theorems we provide. You will need to define and prove helper lemmas,
as before.
Make sure Lean accepts the whole file before submitting.
Substitution is defined exactly as it was for the STLC, with one clause per new constructor.
Why the definition is wrapped in a section
Substitution is written using its own [x := s] t notation, which is being
defined at the same time, so — as in the Stlc chapter — the rule
is first declared local, with hygiene off so that the subst in its expansion
refers to the function being defined, and then declared again for real once the
section closes.
section
set_option hygiene false in
local macro_rules (kind := Stlc.tmBracket)
| `(<{ [$x := $s] $t }>) => do
`(subst $(← Stlc.varStr x) <{ $s:stlcTm }> <{ $t:stlcTm }>)
def subst (x : String) (s : Tm) (t : Tm) : Tm := solution!(
match t with
-- `.var y`, not `<{ ~y }>`: `y` is the variable's *name*, a `String`.
| .var y =>
if x = y then s else t
| <{ λ ~y : ~τ . ~t₁ }> =>
if x = y then t else <{ λ ~y : ~τ . [~x := ~s] ~t₁ }>
| <{ ~t₁ ~t₂ }> =>
<{ ([~x := ~s] ~t₁) ([~x := ~s] ~t₂) }>
| .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₃ }>)
end
macro_rules (kind := Stlc.tmBracket)
| `(<{ [$x := $s] $t }>) => do
`(subst $(← Stlc.varStr x) <{ $s:stlcTm }> <{ $t:stlcTm }>)
Notation encoding: substitution
One more line registers substitutions with the printer, so that a goal
mentioning one reads as [x := s] t rather than as a subst application.
open Lean PrettyPrinter Delaborator SubExpr in
@[delab app.StlcArith.subst]
def delabSubst : Delab := whenPPOption getPPNotation do
match ← delabTmInner with
| `(stlcTm| ~$e) => pure e
| e => `(<{ $e:stlcTm }>)
You will also want one @[simp] simplification lemma per constructor, saying
how your subst behaves on that constructor, in the style of the
Stlc chapter — the substitution lemma below is proved by
rewriting with them rather than by unfolding the definition. Two of the
constructors need two lemmas apiece, since substitution treats a bound name
differently depending on whether it is the name being substituted for.
section
variable (x y : String) (s t t₁ t₂ t₃ : Tm) (τ : Ty) (n : Nat)
@[simp] theorem subst_var_eq : <{ [~x := ~s] ~(Tm.var x) }> = s := by x:Strings:Tm⊢ <{ [~x := s] ~(StlcArith.Tm.var x) }> = s
simp [subst] All goals completed! 🐙
@[simp] theorem subst_var_ne (h : x ≠ y) : <{ [~x := ~s] ~(Tm.var y) }> = .var y := by x:Stringy:Strings:Tmh:x ≠ y⊢ <{ [~x := s] ~(StlcArith.Tm.var y) }> = StlcArith.Tm.var y
simp [subst, h] All goals completed! 🐙
@[simp] theorem subst_abs_eq : <{ [~x := ~s] (λ ~x : ~τ . ~t) }> = <{ λ ~x : ~τ . ~t }> := by x:Strings:Tmt:Tmτ:Ty⊢ <{ [~x := s] (λ ~x : τ . t) }> = <{ λ ~x : τ . t }>
simp [subst] All goals completed! 🐙
@[simp] theorem subst_abs_ne (h : x ≠ y) :
<{ [~x := ~s] (λ ~y : ~τ . ~t) }> = <{ λ ~y : ~τ . [~x := ~s] ~t }> := by x:Stringy:Strings:Tmt:Tmτ:Tyh:x ≠ y⊢ <{ [~x := s] (λ ~y : τ . t) }> = <{ λ ~y : τ . [~x := s] t }>
simp [subst, h] All goals completed! 🐙
@[simp] theorem subst_app :
<{ [~x := ~s] (~t₁ ~t₂) }> = <{ ([~x := ~s] ~t₁) ([~x := ~s] ~t₂) }> := rfl
@[simp] theorem subst_const : <{ [~x := ~s] ~(Tm.const n) }> = .const n := rfl
@[simp] theorem subst_succ :
<{ [~x := ~s] (succ ~t₁) }> = <{ succ ([~x := ~s] ~t₁) }> := rfl
@[simp] theorem subst_pred :
<{ [~x := ~s] (pred ~t₁) }> = <{ pred ([~x := ~s] ~t₁) }> := rfl
@[simp] theorem subst_mult :
<{ [~x := ~s] (~t₁ * ~t₂) }> = <{ ([~x := ~s] ~t₁) * ([~x := ~s] ~t₂) }> := rfl
@[simp] theorem subst_ite0 :
<{ [~x := ~s] (if0 ~t₁ then ~t₂ else ~t₃) }> =
<{ if0 [~x := ~s] ~t₁ then [~x := ~s] ~t₂ else [~x := ~s] ~t₃ }> := rfl
end
Next, the values.
inductive Tm.IsValue : Tm → Prop where
-- In the pure STLC, function abstractions were the only values:
| abs (x : String) (τ₂ : Ty) (t₁ : Tm) : Tm.IsValue <{ λ ~x : ~τ₂ . ~t₁ }>
-- now the numbers are values too.
| const (n : Nat) : Tm.IsValue (.const n)
Now the reduction relation.
section
set_option hygiene false in
local notation:40 t:41 " ⟶ " t':41 => Step t t'
inductive Step : Tm → Tm → Prop where
-- The three rules for application are from STLC;
| appAbs (x : String) (τ : Ty) (t v : Tm) (hv : v.IsValue) :
<{ (λ ~x : ~τ . ~t) ~v }> ⟶ <{ [~x := ~v] ~t }>
| app1 (t₁ t₁' t₂ : Tm) (h : t₁ ⟶ t₁') :
<{ ~t₁ ~t₂ }> ⟶ <{ ~t₁' ~t₂ }>
| app2 (v₁ t₂ t₂' : Tm) (hv : v₁.IsValue) (h : t₂ ⟶ t₂') :
<{ ~v₁ ~t₂ }> ⟶ <{ ~v₁ ~t₂' }>
-- the rest say how the arithmetic operators evaluate their arguments and
-- what they compute once those arguments are numbers.
| succ (t₁ t₁' : Tm) (h : t₁ ⟶ t₁') :
<{ succ ~t₁ }> ⟶ <{ succ ~t₁' }>
| succConst (n : Nat) :
<{ succ ~(Tm.const n) }> ⟶ Tm.const (1 + n)
| 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₂)
| mult1 (t₁ t₁' t₂ : Tm) (h : t₁ ⟶ t₁') :
<{ ~t₁ * ~t₂ }> ⟶ <{ ~t₁' * ~t₂ }>
| mult2 (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₃
end
scoped notation:40 t:41 " ⟶ " t':41 => Step t t'
scoped notation:40 t:41 " ⟶* " t':41 => Multi Step t t'
An example:
-- Our solution uses [normalize]. It is fine if the student either follows this
-- strategy or proceeds by hand.
attribute [StlcArithEval] Tm.IsValue.abs Tm.IsValue.const
attribute [StlcArithEval] Step.appAbs Step.app1 Step.app2 Step.succ Step.succConst
Step.pred Step.predConst Step.multConst Step.mult1 Step.mult2 Step.if0Step
Step.if0Zero Step.if0Nonzero
theorem Nat_step_example : ∃ t, <{ (λ x : Nat . λ y : Nat . x * y) 3 2 }> ⟶* t := by ⊢ ∃ t, <{ (λ x : Nat . λ y : Nat . x * y) 3 2 }> ⟶* t
solution!
exists <{ 6 }> ⊢ <{ (λ x : Nat . λ y : Nat . x * y) 3 2 }> ⟶* <{ 6 }>
normalize using StlcArithEval All goals completed! 🐙
The reduction example above ought to be joined by a bigger one — something to replace the factorial example that used to live here.
A typing context is a partial map from variables to types, exactly as before.
abbrev Context := PartialMap String Ty
Notation 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.
open Lean in
/-- The `Context` denoted by a context expression. -/
partial def ctxTerm (Γ : TSyntax `stlcCtx) : MacroM Term :=
match Γ with
| `(stlcCtx| ∅) => `((∅ : Context))
| `(stlcCtx| ~$e) => pure e
| `(stlcCtx| $x:stlcVar ↦ $τ:stlcTy ; $Γ:stlcCtx) => do
`(PartialMap.update $(← ctxTerm Γ) $(← Stlc.varStr x) <{ $τ:stlcTy }>)
| _ => Macro.throwUnsupported
section StlcArith
set_option hygiene false in
local macro_rules (kind := Stlc.judgeBracket)
| `(<{ $Γ:stlcCtx ⊢ $t:stlcTm ⦂ $τ:stlcTy }>) => do
`(HasType $(← ctxTerm Γ) <{ $t:stlcTm }> <{ $τ:stlcTy }>)
Now the typing relation.
inductive HasType : Context → Tm → Ty → Prop where
-- The typing rules for variables, abstraction, and application are from 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₂ ⦂ ~τ₁ }>
-- The remaining five are the typing rules for arithmetic expressions.
| 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₃ ⦂ ~τ₀ }>
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.
end StlcArith
scoped macro_rules (kind := Stlc.judgeBracket)
| `(<{ $Γ:stlcCtx ⊢ $t:stlcTm ⦂ $τ:stlcTy }>) => do
`(HasType $(← ctxTerm Γ) <{ $t:stlcTm }> <{ $τ:stlcTy }>)
open Lean PrettyPrinter in
/-- 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. -/
partial def unexpandCtx : Term → UnexpandM (TSyntax `stlcCtx)
| `(∅) => `(stlcCtx| ∅)
| `($x:str →ₚ $τ) => do
unexpandCtx (← `($x →ₚ $τ ; ∅))
| `($x:str →ₚ $τ ; $Γ) => do
let Γ' ← unexpandCtx Γ
let x' : TSyntax `stlcVar ←
if Stlc.isPlainName x.getString then
`(stlcVar| $(mkIdent (Name.mkSimple x.getString)):ident)
else `(stlcVar| ~$x)
match τ with
| `(<{ $τ':stlcTy }>) => `(stlcCtx| $x':stlcVar ↦ $τ' ; $Γ')
| _ => `(stlcCtx| $x':stlcVar ↦ ~($τ) ; $Γ')
| Γ => `(stlcCtx| ~($Γ))
open Lean PrettyPrinter in
@[app_unexpander StlcArith.HasType]
def HasType.unexpand : Unexpander
| `($_ $Γ <{ $t:stlcTm }> <{ $τ:stlcTy }>) =>
do `(<{ $(← unexpandCtx Γ) ⊢ $t ⦂ $τ }>)
| `($_ $Γ <{ $t:stlcTm }> $τ) =>
do `(<{ $(← unexpandCtx Γ) ⊢ $t ⦂ ~($τ) }>)
| `($_ $Γ $t <{ $τ:stlcTy }>) =>
do `(<{ $(← unexpandCtx Γ) ⊢ ~($t) ⦂ $τ }>)
| `($_ $Γ $t $τ) =>
do `(<{ $(← unexpandCtx Γ) ⊢ ~($t) ⦂ ~($τ) }>)
| _ => throw ()
An example:
theorem Nat_typing_example : <{ ∅ ⊢ (λ x : Nat . λ y : Nat . x * y) 3 2 ⦂ Nat }> := by ⊢ <{ ∅ ⊢ (λ x : Nat . λ y : Nat . x * y) 3 2 ⦂ Nat }>
solution!
apply HasType.app (τ₂ := Ty.nat) h₁ ⊢ <{ ∅ ⊢ (λ x : Nat . λ y : Nat . x * y) 3 ⦂ Nat → Nat }>h₂ ⊢ <{ ∅ ⊢ 2 ⦂ Nat }>
· h₁ ⊢ <{ ∅ ⊢ (λ x : Nat . λ y : Nat . x * y) 3 ⦂ Nat → Nat }> apply HasType.app (τ₂ := Ty.nat) h₁.h₁ ⊢ <{ ∅ ⊢ λ x : Nat . λ y : Nat . x * y ⦂ Nat → Nat → Nat }>h₁.h₂ ⊢ <{ ∅ ⊢ 3 ⦂ Nat }>
· h₁.h₁ ⊢ <{ ∅ ⊢ λ x : Nat . λ y : Nat . x * y ⦂ Nat → Nat → Nat }> apply HasType.abs h₁.h₁ ⊢ <{ x ↦ Nat ; ∅ ⊢ λ y : Nat . x * y ⦂ Nat → Nat }>
apply HasType.abs h₁.h₁ ⊢ <{ y ↦ Nat ; x ↦ Nat ; ∅ ⊢ x * y ⦂ Nat }>
apply HasType.mult h₁.h₁.h₁ ⊢ <{ y ↦ Nat ; x ↦ Nat ; ∅ ⊢ x ⦂ Nat }>h₁.h₁.h₂ ⊢ <{ y ↦ Nat ; x ↦ Nat ; ∅ ⊢ y ⦂ Nat }>
· h₁.h₁.h₁ ⊢ <{ y ↦ Nat ; x ↦ Nat ; ∅ ⊢ x ⦂ Nat }> apply HasType.var h₁.h₁.h₁ ⊢ ("y" →ₚ <{ Nat }> ; "x" →ₚ <{ Nat }>)["x"] = some <{ Nat }>
rfl All goals completed! 🐙
· h₁.h₁.h₂ ⊢ <{ y ↦ Nat ; x ↦ Nat ; ∅ ⊢ y ⦂ Nat }> apply HasType.var h₁.h₁.h₂ ⊢ ("y" →ₚ <{ Nat }> ; "x" →ₚ <{ Nat }>)["y"] = some <{ Nat }>
rfl All goals completed! 🐙
· h₁.h₂ ⊢ <{ ∅ ⊢ 3 ⦂ Nat }> apply HasType.const All goals completed! 🐙
· h₂ ⊢ <{ ∅ ⊢ 2 ⦂ Nat }> apply HasType.const All goals completed! 🐙
6.7.1.1. The Technical Theorems
The next lemmas are proved exactly as before.
theorem weakening (Γ Γ' : Context) (t : Tm) (τ : Ty)
(hi : Γ ⊆ Γ') (hτ : <{ ~Γ ⊢ ~t ⦂ ~τ }>) : <{ ~Γ' ⊢ ~t ⦂ ~τ }> := by Γ:ContextΓ':Contextt:Tmτ:Tyhi:Γ ⊆ Γ'hτ:<{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ~(Γ') ⊢ ~(t) ⦂ ~(τ) }>
solution!
induction hτ generalizing Γ' with
| var _ x _ h => var Γ:Contextt:Tmτ:TyΓ✝:Contextx:Stringτ₁✝:Tyh:Γ✝[x] = some τ₁✝Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(StlcArith.Tm.var x) ⦂ ~(τ₁✝) }>
constructor var Γ:Contextt:Tmτ:TyΓ✝:Contextx:Stringτ₁✝:Tyh:Γ✝[x] = some τ₁✝Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ'[x] = some τ₁✝
exact hi h All goals completed! 🐙
| abs _ x _ _ _ _ ih => abs Γ:Contextt:Tmτ:TyΓ✝:Contextx:Stringτ₁✝:Tyτ₂✝:Tyt₁✝:Tmh✝:<{ ~(x →ₚ τ₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>ih:∀ (Γ' : Context), x →ₚ τ₂✝ ; Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ λ ~x : τ₂✝ . t₁✝ ⦂ τ₂✝ → τ₁✝ }>
constructor abs Γ:Contextt:Tmτ:TyΓ✝:Contextx:Stringτ₁✝:Tyτ₂✝:Tyt₁✝:Tmh✝:<{ ~(x →ₚ τ₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>ih:∀ (Γ' : Context), x →ₚ τ₂✝ ; Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(x →ₚ τ₂✝ ; Γ') ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>
apply ih abs Γ:Contextt:Tmτ:TyΓ✝:Contextx:Stringτ₁✝:Tyτ₂✝:Tyt₁✝:Tmh✝:<{ ~(x →ₚ τ₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>ih:∀ (Γ' : Context), x →ₚ τ₂✝ ; Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ x →ₚ τ₂✝ ; Γ✝ ⊆ x →ₚ τ₂✝ ; Γ'
apply PartialMap.update_subset abs Γ:Contextt:Tmτ:TyΓ✝:Contextx:Stringτ₁✝:Tyτ₂✝:Tyt₁✝:Tmh✝:<{ ~(x →ₚ τ₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>ih:∀ (Γ' : Context), x →ₚ τ₂✝ ; Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ'
assumption All goals completed! 🐙
| app _ _ _ _ _ _ _ ih₁ ih₂ => app Γ:Contextt:Tmτ:TyΓ✝:Contextτ₁✝:Tyτ₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ t₁✝ t₂✝ ⦂ ~(τ₁✝) }>
constructor app.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextτ₁✝:Tyτ₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~?app.τ₂ → τ₁✝ }>app.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextτ₁✝:Tyτ₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(?app.τ₂) }>app.τ₂ Γ:Contextt:Tmτ:TyΓ✝:Contextτ₁✝:Tyτ₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Ty
· app.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextτ₁✝:Tyτ₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~?app.τ₂ → τ₁✝ }> apply ih₁ app.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextτ₁✝:Tyτ₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ'
exact hi All goals completed! 🐙
· app.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextτ₁✝:Tyτ₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }> apply ih₂ app.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextτ₁✝:Tyτ₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ'
exact hi All goals completed! 🐙
| const _ n => const Γ:Contextt:Tmτ:TyΓ✝:Contextn:NatΓ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(StlcArith.Tm.const n) ⦂ Nat }> constructor All goals completed! 🐙
| succ _ _ _ ih => succ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmh✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>ih:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ succ t₁✝ ⦂ Nat }>
constructor succ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmh✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>ih:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>
apply ih succ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmh✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>ih:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ'
exact hi All goals completed! 🐙
| pred _ _ _ ih => pred Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmh✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>ih:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ pred t₁✝ ⦂ Nat }>
constructor pred Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmh✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>ih:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>
apply ih pred Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmh✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>ih:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ'
exact hi All goals completed! 🐙
| mult _ _ _ _ _ ih₁ ih₂ => mult Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ Nat }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ t₁✝ * t₂✝ ⦂ Nat }>
constructor mult.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ Nat }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>mult.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ Nat }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }>
· mult.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ Nat }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }> apply ih₁ mult.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ Nat }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ'
exact hi All goals completed! 🐙
· mult.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ Nat }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }> apply ih₂ mult.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ Nat }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ'
exact hi All goals completed! 🐙
| ite0 _ _ _ _ _ _ _ _ ih₁ ih₂ ih₃ => ite0 Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:Tmτ₀✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>ih₃:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ if0 t₁✝ then t₂✝ else t₃✝ ⦂ ~(τ₀✝) }>
constructor ite0.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:Tmτ₀✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>ih₃:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ite0.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:Tmτ₀✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>ih₃:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>ite0.h₃ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:Tmτ₀✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>ih₃:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>
· ite0.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:Tmτ₀✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>ih₃:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }> apply ih₁ ite0.h₁ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:Tmτ₀✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>ih₃:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ'
exact hi All goals completed! 🐙
· ite0.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:Tmτ₀✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>ih₃:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }> apply ih₂ ite0.h₂ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:Tmτ₀✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>ih₃:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ'
exact hi All goals completed! 🐙
· ite0.h₃ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:Tmτ₀✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>ih₃:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }> apply ih₃ ite0.h₃ Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmt₃✝:Tmτ₀✝:Tyh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>h₃✝:<{ ~(Γ✝) ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₀✝) }>ih₃:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₃✝) ⦂ ~(τ₀✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ'
exact hi All goals completed! 🐙
The two helper lemmas that weakening is for are also proved just as they were for the STLC.
theorem weakening_empty (Γ : Context) (t : Tm) (τ : Ty) (hτ : <{ ∅ ⊢ ~t ⦂ ~τ }>) :
<{ ~Γ ⊢ ~t ⦂ ~τ }> := by Γ:Contextt:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>
apply weakening ∅ hi Γ:Contextt:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ ∅ ⊆ Γhτ Γ:Contextt:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ∅ ⊢ ~(t) ⦂ ~(τ) }>
· hi Γ:Contextt:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ ∅ ⊆ Γ intros x b contra hi Γ:Contextt:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>x:Stringb:Tycontra:∅[x] = some b⊢ Γ[x] = some b
contradiction All goals completed! 🐙
· hτ Γ:Contextt:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ∅ ⊢ ~(t) ⦂ ~(τ) }> assumption All goals completed! 🐙
theorem substitution_preserves_typing (Γ : Context) (x : String) (τ' : Ty)
(t v : Tm) (τ : Ty)
(hτ : <{ ~x ↦ ~τ' ; ~Γ ⊢ ~t ⦂ ~τ }>) (hv : <{ ∅ ⊢ ~v ⦂ ~τ' }>) :
<{ ~Γ ⊢ [~x := ~v] ~t ⦂ ~τ }> := by Γ:Contextx:Stringτ':Tyt:Tmv:Tmτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>hv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>⊢ <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>
induction t generalizing Γ τ with
| var y => var x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(StlcArith.Tm.var y) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var y) ⦂ ~(τ) }>
cases hτ with
| var _ _ _ h => var.var x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τ⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var y) ⦂ ~(τ) }>
by_cases hxy : x = y pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τhxy:x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var y) ⦂ ~(τ) }>neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var y) ⦂ ~(τ) }>
· pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τhxy:x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var y) ⦂ ~(τ) }> subst hxy pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[x] = some τ⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var x) ⦂ ~(τ) }>
rw [PartialMap.update_eq pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τ⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var x) ⦂ ~(τ) }>] at h pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τ⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var x) ⦂ ~(τ) }>
rw [subst_var_eq pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τ⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ) }>] pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τ⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ) }>
have hτ'τ : τ' = τ := by Γ:Contextx:Stringτ':Tyt:Tmv:Tmτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>hv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>⊢ <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }>
apply Option.some.inj x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τ⊢ some τ' = some τ
exact h pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τhτ'τ:τ' = τ⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ) }>
subst hτ'τ pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contexth:some τ' = some τ'⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ') }>
apply weakening_empty pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contexth:some τ' = some τ'⊢ <{ ∅ ⊢ ~(v) ⦂ ~(τ') }>
exact hv All goals completed! 🐙
· neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var y) ⦂ ~(τ) }> rw [PartialMap.update_neq hxy neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var y) ⦂ ~(τ) }>] at h neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var y) ⦂ ~(τ) }>
rw [subst_var_ne _ _ _ hxy neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ ~(StlcArith.Tm.var y) ⦂ ~(τ) }>] neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ ~(StlcArith.Tm.var y) ⦂ ~(τ) }>
constructor neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τhxy:¬x = y⊢ Γ[y] = some τ
exact h All goals completed! 🐙
| app t₁ t₂ ih₁ ih₂ => app x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ t₁ t₂ ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] (t₁ t₂) ⦂ ~(τ) }>
cases hτ with
| app _ _ _ _ _ h₁ h₂ => app.app x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:Tyτ₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ τ₂✝ → τ }>⊢ <{ ~(Γ) ⊢ [~x := v] (t₁ t₂) ⦂ ~(τ) }>
rw [subst_app app.app x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:Tyτ₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ τ₂✝ → τ }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ [~x := v] t₂ ⦂ ~(τ) }>] app.app x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:Tyτ₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ τ₂✝ → τ }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ [~x := v] t₂ ⦂ ~(τ) }>
constructor app.app.h₁ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:Tyτ₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ τ₂✝ → τ }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~?app.app.τ₂ → τ }>app.app.h₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:Tyτ₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ τ₂✝ → τ }>⊢ <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(?app.app.τ₂) }>app.app.τ₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:Tyτ₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ τ₂✝ → τ }>⊢ Ty
· app.app.h₁ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:Tyτ₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ τ₂✝ → τ }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~?app.app.τ₂ → τ }> apply ih₁ app.app.h₁ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:Tyτ₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ τ₂✝ → τ }>⊢ <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~?app.app.τ₂ → τ }>
exact h₁ All goals completed! 🐙
· app.app.h₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:Tyτ₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ τ₂✝ → τ }>⊢ <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ₂✝) }> apply ih₂ app.app.h₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:Tyτ₂✝:Tyh₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ₂✝) }>h₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ τ₂✝ → τ }>⊢ <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ₂✝) }>
exact h₂ All goals completed! 🐙
| abs y σ t₁ ih => abs x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ λ ~y : σ . t₁ ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : σ . t₁) ⦂ ~(τ) }>
cases hτ with
| abs _ _ _ _ _ h => abs.abs x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(y →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : σ . t₁) ⦂ σ → τ₁✝ }>
by_cases hxy : x = y pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(y →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>hxy:x = y⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : σ . t₁) ⦂ σ → τ₁✝ }>neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(y →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>hxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : σ . t₁) ⦂ σ → τ₁✝ }>
· pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(y →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>hxy:x = y⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : σ . t₁) ⦂ σ → τ₁✝ }> subst hxy pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~x : σ . t₁) ⦂ σ → τ₁✝ }>
rw [subst_abs_eq pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>⊢ <{ ~(Γ) ⊢ λ ~x : σ . t₁ ⦂ σ → τ₁✝ }>] pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>⊢ <{ ~(Γ) ⊢ λ ~x : σ . t₁ ⦂ σ → τ₁✝ }>
rw [PartialMap.update_shadow pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>⊢ <{ ~(Γ) ⊢ λ ~x : σ . t₁ ⦂ σ → τ₁✝ }>] at h pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>⊢ <{ ~(Γ) ⊢ λ ~x : σ . t₁ ⦂ σ → τ₁✝ }>
constructor pos x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>⊢ <{ ~(x →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>
exact h All goals completed! 🐙
· neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(y →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>hxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~y : σ . t₁) ⦂ σ → τ₁✝ }> rw [subst_abs_ne _ _ _ _ _ hxy neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(y →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>hxy:¬x = y⊢ <{ ~(Γ) ⊢ λ ~y : σ . [~x := v] t₁ ⦂ σ → τ₁✝ }>] neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(y →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>hxy:¬x = y⊢ <{ ~(Γ) ⊢ λ ~y : σ . [~x := v] t₁ ⦂ σ → τ₁✝ }>
rw [PartialMap.update_permute (Ne.symm hxy) neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ τ' ; y →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>hxy:¬x = y⊢ <{ ~(Γ) ⊢ λ ~y : σ . [~x := v] t₁ ⦂ σ → τ₁✝ }>] at h neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ τ' ; y →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>hxy:¬x = y⊢ <{ ~(Γ) ⊢ λ ~y : σ . [~x := v] t₁ ⦂ σ → τ₁✝ }>
constructor neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ τ' ; y →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>hxy:¬x = y⊢ <{ ~(y →ₚ σ ; Γ) ⊢ [~x := v] t₁ ⦂ ~(τ₁✝) }>
apply ih neg x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:Stringσ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ τ' ; y →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>hxy:¬x = y⊢ <{ ~(x →ₚ τ' ; y →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>
exact h All goals completed! 🐙
| const n => const x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>n:NatΓ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(StlcArith.Tm.const n) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.const n) ⦂ ~(τ) }>
cases hτ with
| const => const.const x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>n:NatΓ:Context⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.const n) ⦂ Nat }>
rw [subst_const const.const x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>n:NatΓ:Context⊢ <{ ~(Γ) ⊢ ~(StlcArith.Tm.const n) ⦂ Nat }>] const.const x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>n:NatΓ:Context⊢ <{ ~(Γ) ⊢ ~(StlcArith.Tm.const n) ⦂ Nat }>
constructor All goals completed! 🐙
| succ t₁ ih => succ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ succ t₁ ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] (succ t₁) ⦂ ~(τ) }>
cases hτ with
| succ _ _ h => succ.succ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ [~x := v] (succ t₁) ⦂ Nat }>
rw [subst_succ succ.succ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ succ [~x := v] t₁ ⦂ Nat }>] succ.succ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ succ [~x := v] t₁ ⦂ Nat }>
constructor succ.succ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ Nat }>
apply ih succ.succ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>
exact h All goals completed! 🐙
| pred t₁ ih => pred x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ pred t₁ ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] (pred t₁) ⦂ ~(τ) }>
cases hτ with
| pred _ _ h => pred.pred x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ [~x := v] (pred t₁) ⦂ Nat }>
rw [subst_pred pred.pred x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ pred [~x := v] t₁ ⦂ Nat }>] pred.pred x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ pred [~x := v] t₁ ⦂ Nat }>
constructor pred.pred x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ Nat }>
apply ih pred.pred x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>
exact h All goals completed! 🐙
| mult t₁ t₂ ih₁ ih₂ => mult x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ t₁ * t₂ ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] (t₁ * t₂) ⦂ ~(τ) }>
cases hτ with
| mult _ _ _ h₁ h₂ => mult.mult x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contexth₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ [~x := v] (t₁ * t₂) ⦂ Nat }>
rw [subst_mult mult.mult x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contexth₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ * [~x := v] t₂ ⦂ Nat }>] mult.mult x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contexth₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ * [~x := v] t₂ ⦂ Nat }>
constructor mult.mult.h₁ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contexth₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ Nat }>mult.mult.h₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contexth₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ Nat }>
· mult.mult.h₁ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contexth₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ Nat }> apply ih₁ mult.mult.h₁ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contexth₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ Nat }>⊢ <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>
exact h₁ All goals completed! 🐙
· mult.mult.h₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contexth₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ Nat }> apply ih₂ mult.mult.h₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>Γ:Contexth₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ Nat }>⊢ <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ Nat }>
exact h₂ All goals completed! 🐙
| ite0 t₁ t₂ t₃ ih₁ ih₂ ih₃ => ite0 x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmt₃:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>ih₃:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₃ ⦂ ~(τ) }>Γ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ if0 t₁ then t₂ else t₃ ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] (if0 t₁ then t₂ else t₃) ⦂ ~(τ) }>
cases hτ with
| ite0 _ _ _ _ _ h₁ h₂ h₃ => ite0.ite0 x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmt₃:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>ih₃:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₃ ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] (if0 t₁ then t₂ else t₃) ⦂ ~(τ) }>
rw [subst_ite0 ite0.ite0 x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmt₃:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>ih₃:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₃ ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ if0 [~x := v] t₁ then [~x := v] t₂ else [~x := v] t₃ ⦂ ~(τ) }>] ite0.ite0 x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmt₃:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>ih₃:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₃ ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ if0 [~x := v] t₁ then [~x := v] t₂ else [~x := v] t₃ ⦂ ~(τ) }>
constructor ite0.ite0.h₁ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmt₃:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>ih₃:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₃ ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ Nat }>ite0.ite0.h₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmt₃:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>ih₃:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₃ ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>ite0.ite0.h₃ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmt₃:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>ih₃:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₃ ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] t₃ ⦂ ~(τ) }>
· ite0.ite0.h₁ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmt₃:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>ih₃:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₃ ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ Nat }> apply ih₁ ite0.ite0.h₁ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmt₃:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>ih₃:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₃ ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }>⊢ <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>
exact h₁ All goals completed! 🐙
· ite0.ite0.h₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmt₃:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>ih₃:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₃ ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }> apply ih₂ ite0.ite0.h₂ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmt₃:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>ih₃:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₃ ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }>⊢ <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }>
exact h₂ All goals completed! 🐙
· ite0.ite0.h₃ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmt₃:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>ih₃:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₃ ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] t₃ ⦂ ~(τ) }> apply ih₃ ite0.ite0.h₃ x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmt₂:Tmt₃:Tmih₁:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>ih₂:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₂ ⦂ ~(τ) }>ih₃:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₃ ⦂ ~(τ) }>Γ:Contextτ:Tyh₁:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₂) ⦂ ~(τ) }>h₃:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }>⊢ <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₃) ⦂ ~(τ) }>
exact h₃ All goals completed! 🐙
6.7.1.2. Preservation
Hint: you will need to define and prove the same helper lemmas we used before.
theorem preservation (t t' : Tm) (τ : Ty)
(hτ : <{ ∅ ⊢ ~t ⦂ ~τ }>) (hs : t ⟶ t') : <{ ∅ ⊢ ~t' ⦂ ~τ }> := by t:Tmt':Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>hs:t ⟶ t'⊢ <{ ∅ ⊢ ~(t') ⦂ ~(τ) }>
solution!
generalize hΓ : (∅ : Context) = Γ at hτ t:Tmt':Tmτ:Tyhs:t ⟶ t'Γ:ContexthΓ:∅ = Γhτ:<{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ ~(t') ⦂ ~(τ) }>
induction hτ generalizing t' with
| var => var t:Tmτ:TyΓ:ContextΓ✝:Contextx✝:Stringτ₁✝:Tyh✝:Γ✝[x✝] = some τ₁✝t':Tmhs:StlcArith.Tm.var x✝ ⟶ t'hΓ:∅ = Γ✝⊢ <{ ~(Γ✝) ⊢ ~(t') ⦂ ~(τ₁✝) }> cases hs All goals completed! 🐙
| abs => abs t:Tmτ:TyΓ:ContextΓ✝:Contextx✝:Stringτ₁✝:Tyτ₂✝:Tyt₁✝:Tmh✝:<{ ~(x✝ →ₚ τ₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>h_ih✝:∀ (t' : Tm), t₁✝ ⟶ t' → ∅ = x✝ →ₚ τ₂✝ ; Γ✝ → <{ ~(x✝ →ₚ τ₂✝ ; Γ✝) ⊢ ~(t') ⦂ ~(τ₁✝) }>t':Tmhs:<{ λ ~x✝ : τ₂✝ . t₁✝ }> ⟶ t'hΓ:∅ = Γ✝⊢ <{ ~(Γ✝) ⊢ ~(t') ⦂ τ₂✝ → τ₁✝ }> cases hs All goals completed! 🐙
| const => const t:Tmτ:TyΓ:ContextΓ✝:Contextn✝:Natt':Tmhs:StlcArith.Tm.const n✝ ⟶ t'hΓ:∅ = Γ✝⊢ <{ ~(Γ✝) ⊢ ~(t') ⦂ Nat }> cases hs All goals completed! 🐙
| app Γ τ₁ τ₂ t₁ t₂ h₁ h₂ ih₁ ih₂ => app t:Tmτ:TyΓ✝:ContextΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ~(Γ) ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ~(Γ) ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = Γ → <{ ~(Γ) ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = Γ → <{ ~(Γ) ⊢ ~(t') ⦂ ~(τ₂) }>t':Tmhs:<{ t₁ t₂ }> ⟶ t'hΓ:∅ = Γ⊢ <{ ~(Γ) ⊢ ~(t') ⦂ ~(τ₁) }>
subst hΓ app t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmt':Tmhs:<{ t₁ t₂ }> ⟶ t'h₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>⊢ <{ ∅ ⊢ ~(t') ⦂ ~(τ₁) }>
cases hs with
| appAbs _ _ _ _ _ => app.appAbs 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') ⦂ τ₂ → τ₁ }>hv✝:t₂.IsValue⊢ <{ ∅ ⊢ [~x✝ := t₂] t✝ ⦂ ~(τ₁) }>
-- The one interesting case: the desired result is the substitution lemma.
cases h₁ with
| abs _ _ _ _ _ hb => app.appAbs.abs t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>x✝:Stringt✝:Tmhv✝:t₂.IsValueih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂ . t✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>hb:<{ ~(x✝ →ₚ τ₂) ⊢ ~(t✝) ⦂ ~(τ₁) }>⊢ <{ ∅ ⊢ [~x✝ := t₂] t✝ ⦂ ~(τ₁) }>
apply substitution_preserves_typing app.appAbs.abs.hτ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>x✝:Stringt✝:Tmhv✝:t₂.IsValueih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂ . t✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>hb:<{ ~(x✝ →ₚ τ₂) ⊢ ~(t✝) ⦂ ~(τ₁) }>⊢ <{ ~(x✝ →ₚ ?app.appAbs.abs.τ') ⊢ ~(t✝) ⦂ ~(τ₁) }>app.appAbs.abs.hv t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>x✝:Stringt✝:Tmhv✝:t₂.IsValueih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂ . t✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>hb:<{ ~(x✝ →ₚ τ₂) ⊢ ~(t✝) ⦂ ~(τ₁) }>⊢ <{ ∅ ⊢ ~(t₂) ⦂ ~(?app.appAbs.abs.τ') }>app.appAbs.abs.τ' t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>x✝:Stringt✝:Tmhv✝:t₂.IsValueih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂ . t✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>hb:<{ ~(x✝ →ₚ τ₂) ⊢ ~(t✝) ⦂ ~(τ₁) }>⊢ Ty
· app.appAbs.abs.hτ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>x✝:Stringt✝:Tmhv✝:t₂.IsValueih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂ . t✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>hb:<{ ~(x✝ →ₚ τ₂) ⊢ ~(t✝) ⦂ ~(τ₁) }>⊢ <{ ~(x✝ →ₚ ?app.appAbs.abs.τ') ⊢ ~(t✝) ⦂ ~(τ₁) }> exact hb All goals completed! 🐙
· app.appAbs.abs.hv t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>x✝:Stringt✝:Tmhv✝:t₂.IsValueih₁:∀ (t' : Tm), <{ λ ~x✝ : τ₂ . t✝ }> ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>hb:<{ ~(x✝ →ₚ τ₂) ⊢ ~(t✝) ⦂ ~(τ₁) }>⊢ <{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }> exact h₂ All goals completed! 🐙
| app1 _ t₁' _ h => app.app1 t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>t₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ t₁' t₂ ⦂ ~(τ₁) }>
constructor app.app1.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₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₁') ⦂ ~?app.app1.τ₂ → τ₁ }>app.app1.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₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₂) ⦂ ~(?app.app1.τ₂) }>app.app1.τ₂ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>t₁':Tmh:t₁ ⟶ t₁'⊢ Ty
· app.app1.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₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₁') ⦂ ~?app.app1.τ₂ → τ₁ }> apply ih₁ app.app1.h₁.hs t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>t₁':Tmh:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'app.app1.h₁.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₁':Tmh:t₁ ⟶ t₁'⊢ ∅ = ∅
· app.app1.h₁.hs t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>t₁':Tmh:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁' exact h All goals completed! 🐙
· app.app1.h₁.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₁':Tmh:t₁ ⟶ t₁'⊢ ∅ = ∅ rfl All goals completed! 🐙
· app.app1.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₁':Tmh:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }> exact h₂ All goals completed! 🐙
| app2 _ _ t₂' _ h => app.app2 t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>t₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ <{ ∅ ⊢ t₁ t₂' ⦂ ~(τ₁) }>
constructor app.app2.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₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ <{ ∅ ⊢ ~(t₁) ⦂ ~?app.app2.τ₂ → τ₁ }>app.app2.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₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ <{ ∅ ⊢ ~(t₂') ⦂ ~(?app.app2.τ₂) }>app.app2.τ₂ t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>t₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ Ty
· app.app2.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₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ <{ ∅ ⊢ ~(t₁) ⦂ ~?app.app2.τ₂ → τ₁ }> exact h₁ All goals completed! 🐙
· app.app2.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₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ <{ ∅ ⊢ ~(t₂') ⦂ ~(τ₂) }> apply ih₂ app.app2.h₂.hs t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>t₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ t₂ ⟶ t₂'app.app2.h₂.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₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ ∅ = ∅
· app.app2.h₂.hs t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ τ₂ → τ₁ }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ ~(τ₂) }>t₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ t₂ ⟶ t₂' exact h All goals completed! 🐙
· app.app2.h₂.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₂':Tmhv✝:t₁.IsValueh:t₂ ⟶ t₂'⊢ ∅ = ∅ rfl All goals completed! 🐙
| succ Γ t₁ h ih => succ t:Tmτ:TyΓ✝:ContextΓ:Contextt₁:Tmh:<{ ~(Γ) ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = Γ → <{ ~(Γ) ⊢ ~(t') ⦂ Nat }>t':Tmhs:<{ succ t₁ }> ⟶ t'hΓ:∅ = Γ⊢ <{ ~(Γ) ⊢ ~(t') ⦂ Nat }>
subst hΓ succ t:Tmτ:TyΓ:Contextt₁:Tmt':Tmhs:<{ succ t₁ }> ⟶ t'h:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>⊢ <{ ∅ ⊢ ~(t') ⦂ Nat }>
cases hs with
| succ _ t₁' hst => succ.succ t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ succ t₁' ⦂ Nat }>
constructor succ.succ t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₁') ⦂ Nat }>
apply ih succ.succ.hs t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'succ.succ.hΓ t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ ∅ = ∅
· succ.succ.hs t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁' exact hst All goals completed! 🐙
· succ.succ.hΓ t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ ∅ = ∅ rfl All goals completed! 🐙
| succConst n => succ.succConst t:Tmτ:TyΓ:Contextn:Nath:<{ ∅ ⊢ ~(StlcArith.Tm.const n) ⦂ Nat }>ih:∀ (t' : Tm), StlcArith.Tm.const n ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>⊢ <{ ∅ ⊢ ~(StlcArith.Tm.const (1 + n)) ⦂ Nat }> constructor All goals completed! 🐙
| pred Γ t₁ h ih => pred t:Tmτ:TyΓ✝:ContextΓ:Contextt₁:Tmh:<{ ~(Γ) ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = Γ → <{ ~(Γ) ⊢ ~(t') ⦂ Nat }>t':Tmhs:<{ pred t₁ }> ⟶ t'hΓ:∅ = Γ⊢ <{ ~(Γ) ⊢ ~(t') ⦂ Nat }>
subst hΓ pred t:Tmτ:TyΓ:Contextt₁:Tmt':Tmhs:<{ pred t₁ }> ⟶ t'h:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>⊢ <{ ∅ ⊢ ~(t') ⦂ Nat }>
cases hs with
| pred _ t₁' hst => pred.pred t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ pred t₁' ⦂ Nat }>
constructor pred.pred t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₁') ⦂ Nat }>
apply ih pred.pred.hs t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'pred.pred.hΓ t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ ∅ = ∅
· pred.pred.hs t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁' exact hst All goals completed! 🐙
· pred.pred.hΓ t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ ∅ = ∅ rfl All goals completed! 🐙
| predConst n => pred.predConst t:Tmτ:TyΓ:Contextn:Nath:<{ ∅ ⊢ ~(StlcArith.Tm.const n) ⦂ Nat }>ih:∀ (t' : Tm), StlcArith.Tm.const n ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>⊢ <{ ∅ ⊢ ~(StlcArith.Tm.const (n - 1)) ⦂ Nat }> constructor All goals completed! 🐙
| mult Γ t₁ t₂ h₁ h₂ ih₁ ih₂ => mult t:Tmτ:TyΓ✝:ContextΓ:Contextt₁:Tmt₂:Tmh₁:<{ ~(Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(Γ) ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = Γ → <{ ~(Γ) ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = Γ → <{ ~(Γ) ⊢ ~(t') ⦂ Nat }>t':Tmhs:<{ t₁ * t₂ }> ⟶ t'hΓ:∅ = Γ⊢ <{ ~(Γ) ⊢ ~(t') ⦂ Nat }>
subst hΓ mult t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt':Tmhs:<{ t₁ * t₂ }> ⟶ t'h₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>⊢ <{ ∅ ⊢ ~(t') ⦂ Nat }>
cases hs with
| multConst _ _ => mult.multConst t:Tmτ:TyΓ:Contextn₁✝:Natn₂✝:Nath₁:<{ ∅ ⊢ ~(StlcArith.Tm.const n₁✝) ⦂ Nat }>ih₁:∀ (t' : Tm), StlcArith.Tm.const n₁✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>h₂:<{ ∅ ⊢ ~(StlcArith.Tm.const n₂✝) ⦂ Nat }>ih₂:∀ (t' : Tm), StlcArith.Tm.const n₂✝ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>⊢ <{ ∅ ⊢ ~(StlcArith.Tm.const (n₁✝ * n₂✝)) ⦂ Nat }> constructor All goals completed! 🐙
| mult1 _ t₁' _ hst => mult.mult1 t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ t₁' * t₂ ⦂ Nat }>
constructor mult.mult1.h₁ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₁') ⦂ Nat }>mult.mult1.h₂ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₂) ⦂ Nat }>
· mult.mult1.h₁ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₁') ⦂ Nat }> apply ih₁ mult.mult1.h₁.hs t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'mult.mult1.h₁.hΓ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ ∅ = ∅
· mult.mult1.h₁.hs t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁' exact hst All goals completed! 🐙
· mult.mult1.h₁.hΓ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ ∅ = ∅ rfl All goals completed! 🐙
· mult.mult1.h₂ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₂) ⦂ Nat }> exact h₂ All goals completed! 🐙
| mult2 _ _ t₂' _ hst => mult.mult2 t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₂':Tmhv✝:t₁.IsValuehst:t₂ ⟶ t₂'⊢ <{ ∅ ⊢ t₁ * t₂' ⦂ Nat }>
constructor mult.mult2.h₁ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₂':Tmhv✝:t₁.IsValuehst:t₂ ⟶ t₂'⊢ <{ ∅ ⊢ ~(t₁) ⦂ Nat }>mult.mult2.h₂ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₂':Tmhv✝:t₁.IsValuehst:t₂ ⟶ t₂'⊢ <{ ∅ ⊢ ~(t₂') ⦂ Nat }>
· mult.mult2.h₁ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₂':Tmhv✝:t₁.IsValuehst:t₂ ⟶ t₂'⊢ <{ ∅ ⊢ ~(t₁) ⦂ Nat }> exact h₁ All goals completed! 🐙
· mult.mult2.h₂ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₂':Tmhv✝:t₁.IsValuehst:t₂ ⟶ t₂'⊢ <{ ∅ ⊢ ~(t₂') ⦂ Nat }> apply ih₂ mult.mult2.h₂.hs t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₂':Tmhv✝:t₁.IsValuehst:t₂ ⟶ t₂'⊢ t₂ ⟶ t₂'mult.mult2.h₂.hΓ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₂':Tmhv✝:t₁.IsValuehst:t₂ ⟶ t₂'⊢ ∅ = ∅
· mult.mult2.h₂.hs t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₂':Tmhv✝:t₁.IsValuehst:t₂ ⟶ t₂'⊢ t₂ ⟶ t₂' exact hst All goals completed! 🐙
· mult.mult2.h₂.hΓ t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>ih₂:∀ (t' : Tm), t₂ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₂':Tmhv✝:t₁.IsValuehst:t₂ ⟶ t₂'⊢ ∅ = ∅ rfl All goals completed! 🐙
| ite0 Γ t₁ t₂ t₃ τ₀ h₁ h₂ h₃ ih₁ ih₂ ih₃ => ite0 t:Tmτ:TyΓ✝:ContextΓ: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':Tmhs:<{ if0 t₁ then t₂ else t₃ }> ⟶ t'hΓ:∅ = Γ⊢ <{ ~(Γ) ⊢ ~(t') ⦂ ~(τ₀) }>
subst hΓ ite0 t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ₀:Tyt':Tmhs:<{ 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') ⦂ ~(τ₀) }>
cases hs with
| if0Step _ t₁' _ _ hst => ite0.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₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ if0 t₁' then t₂ else t₃ ⦂ ~(τ₀) }>
constructor ite0.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₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₁') ⦂ Nat }>ite0.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₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₂) ⦂ ~(τ₀) }>ite0.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₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₃) ⦂ ~(τ₀) }>
· ite0.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₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₁') ⦂ Nat }> apply ih₁ ite0.if0Step.h₁.hs 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₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'ite0.if0Step.h₁.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₁':Tmhst:t₁ ⟶ t₁'⊢ ∅ = ∅
· ite0.if0Step.h₁.hs 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₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁' exact hst All goals completed! 🐙
· ite0.if0Step.h₁.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₁':Tmhst:t₁ ⟶ t₁'⊢ ∅ = ∅ rfl All goals completed! 🐙
· ite0.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₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₂) ⦂ ~(τ₀) }> exact h₂ All goals completed! 🐙
· ite0.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₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₃) ⦂ ~(τ₀) }> exact h₃ All goals completed! 🐙
| if0Zero => ite0.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₂) ⦂ ~(τ₀) }> exact h₂ All goals completed! 🐙
| if0Nonzero => ite0.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₁:<{ ∅ ⊢ ~(StlcArith.Tm.const (n✝ + 1)) ⦂ Nat }>ih₁:∀ (t' : Tm), StlcArith.Tm.const (n✝ + 1) ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>⊢ <{ ∅ ⊢ ~(t₃) ⦂ ~(τ₀) }> exact h₃ All goals completed! 🐙
6.7.1.3. Progress
theorem progress (t : Tm) (τ : Ty) (hτ : <{ ∅ ⊢ ~t ⦂ ~τ }>) :
t.IsValue ∨ ∃ t', t ⟶ t' := by t:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ t.IsValue ∨ ∃ t', t ⟶ t'
solution!
generalize hΓ : (∅ : Context) = Γ at hτ t:Tmτ:TyΓ:ContexthΓ:∅ = Γhτ:<{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>⊢ t.IsValue ∨ ∃ t', t ⟶ t'
induction hτ with
| var Γ x τ₁ h => var t:Tmτ:TyΓ✝:ContextΓ:Contextx:Stringτ₁:Tyh:Γ[x] = some τ₁hΓ:∅ = Γ⊢ (StlcArith.Tm.var x).IsValue ∨ ∃ t', StlcArith.Tm.var x ⟶ t'
subst hΓ var t:Tmτ:TyΓ:Contextx:Stringτ₁:Tyh:∅[x] = some τ₁⊢ (StlcArith.Tm.var x).IsValue ∨ ∃ t', StlcArith.Tm.var x ⟶ t'
-- Contradictory: variables cannot be typed in an empty context.
rw [PartialMap.getElem_empty var t:Tmτ:TyΓ:Contextx:Stringτ₁:Tyh:none = some τ₁⊢ (StlcArith.Tm.var x).IsValue ∨ ∃ t', StlcArith.Tm.var x ⟶ t'] at h var t:Tmτ:TyΓ:Contextx:Stringτ₁:Tyh:none = some τ₁⊢ (StlcArith.Tm.var x).IsValue ∨ ∃ t', StlcArith.Tm.var x ⟶ t'
cases h All goals completed! 🐙
| abs => abs t:Tmτ:TyΓ:ContextΓ✝:Contextx✝:Stringτ₁✝:Tyτ₂✝:Tyt₁✝:Tmh✝:<{ ~(x✝ →ₚ τ₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>h_ih✝:∅ = x✝ →ₚ τ₂✝ ; Γ✝ → t₁✝.IsValue ∨ ∃ t', t₁✝ ⟶ t'hΓ:∅ = Γ✝⊢ <{ λ ~x✝ : τ₂✝ . t₁✝ }>.IsValue ∨ ∃ t', <{ λ ~x✝ : τ₂✝ . t₁✝ }> ⟶ t'
left abs t:Tmτ:TyΓ:ContextΓ✝:Contextx✝:Stringτ₁✝:Tyτ₂✝:Tyt₁✝:Tmh✝:<{ ~(x✝ →ₚ τ₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>h_ih✝:∅ = x✝ →ₚ τ₂✝ ; Γ✝ → t₁✝.IsValue ∨ ∃ t', t₁✝ ⟶ t'hΓ:∅ = Γ✝⊢ <{ λ ~x✝ : τ₂✝ . t₁✝ }>.IsValue
constructor All goals completed! 🐙
| const _ n => const t:Tmτ:TyΓ:ContextΓ✝:Contextn:NathΓ:∅ = Γ✝⊢ (StlcArith.Tm.const n).IsValue ∨ ∃ t', StlcArith.Tm.const n ⟶ t'
left const t:Tmτ:TyΓ:ContextΓ✝:Contextn:NathΓ:∅ = Γ✝⊢ (StlcArith.Tm.const n).IsValue
constructor All goals completed! 🐙
| app Γ τ₁ τ₂ t₁ t₂ h₁ h₂ ih₁ ih₂ => app t:Tmτ:TyΓ✝:ContextΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ~(Γ) ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ~(Γ) ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = Γ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = Γ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hΓ:∅ = Γ⊢ <{ t₁ t₂ }>.IsValue ∨ ∃ t', <{ t₁ t₂ }> ⟶ t'
right app t:Tmτ:TyΓ✝:ContextΓ: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'
subst hΓ app 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'
cases ih₁ rfl with
| inl hv₁ => app.inl t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValue⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
cases ih₂ rfl with
| inl hv₂ => app.inl.inl t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuehv₂:t₂.IsValue⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
-- `t₁` is a value of arrow type, so it is an abstraction, not a number.
cases hv₁ with
| abs x τ u => app.inl.inl.abs t:Tmτ✝:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₂:t₂.IsValuex:Stringτ:Tyu:Tmh₁:<{ ∅ ⊢ λ ~x : τ . u ⦂ τ₂ → τ₁ }>ih₁:∅ = ∅ → <{ λ ~x : τ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ . u }> ⟶ t'⊢ ∃ t', <{ (λ ~x : τ . u) t₂ }> ⟶ t'
exists <{ [~x := ~t₂] ~u }> app.inl.inl.abs t:Tmτ✝:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₂:t₂.IsValuex:Stringτ:Tyu:Tmh₁:<{ ∅ ⊢ λ ~x : τ . u ⦂ τ₂ → τ₁ }>ih₁:∅ = ∅ → <{ λ ~x : τ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ . u }> ⟶ t'⊢ <{ (λ ~x : τ . u) t₂ }> ⟶ <{ [~x := t₂] u }>
apply Step.appAbs app.inl.inl.abs t:Tmτ✝:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₂:t₂.IsValuex:Stringτ:Tyu:Tmh₁:<{ ∅ ⊢ λ ~x : τ . u ⦂ τ₂ → τ₁ }>ih₁:∅ = ∅ → <{ λ ~x : τ . u }>.IsValue ∨ ∃ t', <{ λ ~x : τ . u }> ⟶ t'⊢ t₂.IsValue
assumption All goals completed! 🐙
| const n => app.inl.inl.const t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₂:t₂.IsValuen:Nath₁:<{ ∅ ⊢ ~(StlcArith.Tm.const n) ⦂ τ₂ → τ₁ }>ih₁:∅ = ∅ → (StlcArith.Tm.const n).IsValue ∨ ∃ t', StlcArith.Tm.const n ⟶ t'⊢ ∃ t', <{ ~(StlcArith.Tm.const n) t₂ }> ⟶ t' cases h₁ All goals completed! 🐙
| inr hs₂ => app.inl.inr t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuehs₂:∃ t', t₂ ⟶ t'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
obtain ⟨t₂', h⟩ := hs₂ app.inl.inr t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
exists <{ ~t₁ ~t₂' }> app.inl.inr t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ <{ t₁ t₂ }> ⟶ <{ t₁ t₂' }>
apply Step.app2 app.inl.inr.hv t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ t₁.IsValueapp.inl.inr.h t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ t₂ ⟶ t₂' <;> app.inl.inr.hv t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ t₁.IsValueapp.inl.inr.h t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ t₂ ⟶ t₂' assumption All goals completed! 🐙
| inr hs₁ => app.inr t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hs₁:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
obtain ⟨t₁', h⟩ := hs₁ app.inr t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t'
exists <{ ~t₁' ~t₂ }> app.inr t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ <{ t₁ t₂ }> ⟶ <{ t₁' t₂ }>
apply Step.app1 app.inr t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'
assumption All goals completed! 🐙
| succ Γ t₁ h ih => succ t:Tmτ:TyΓ✝:ContextΓ:Contextt₁:Tmh:<{ ~(Γ) ⊢ ~(t₁) ⦂ Nat }>ih:∅ = Γ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'hΓ:∅ = Γ⊢ <{ succ t₁ }>.IsValue ∨ ∃ t', <{ succ t₁ }> ⟶ t'
right succ t:Tmτ:TyΓ✝:ContextΓ:Contextt₁:Tmh:<{ ~(Γ) ⊢ ~(t₁) ⦂ Nat }>ih:∅ = Γ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'hΓ:∅ = Γ⊢ ∃ t', <{ succ t₁ }> ⟶ t'
subst hΓ succ t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'⊢ ∃ t', <{ succ t₁ }> ⟶ t'
cases ih rfl with
| inl hv => succ.inl t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'hv:t₁.IsValue⊢ ∃ t', <{ succ t₁ }> ⟶ t'
cases hv with
| abs => succ.inl.abs t:Tmτ:TyΓ:Contextx✝:Stringτ₂✝:Tyt₁✝:Tmh:<{ ∅ ⊢ λ ~x✝ : τ₂✝ . t₁✝ ⦂ Nat }>ih:∅ = ∅ → <{ λ ~x✝ : τ₂✝ . t₁✝ }>.IsValue ∨ ∃ t', <{ λ ~x✝ : τ₂✝ . t₁✝ }> ⟶ t'⊢ ∃ t', <{ succ (λ ~x✝ : τ₂✝ . t₁✝) }> ⟶ t' cases h All goals completed! 🐙
| const n => succ.inl.const t:Tmτ:TyΓ:Contextn:Nath:<{ ∅ ⊢ ~(StlcArith.Tm.const n) ⦂ Nat }>ih:∅ = ∅ → (StlcArith.Tm.const n).IsValue ∨ ∃ t', StlcArith.Tm.const n ⟶ t'⊢ ∃ t', <{ succ ~(StlcArith.Tm.const n) }> ⟶ t'
exists .const (1 + n) succ.inl.const t:Tmτ:TyΓ:Contextn:Nath:<{ ∅ ⊢ ~(StlcArith.Tm.const n) ⦂ Nat }>ih:∅ = ∅ → (StlcArith.Tm.const n).IsValue ∨ ∃ t', StlcArith.Tm.const n ⟶ t'⊢ <{ succ ~(StlcArith.Tm.const n) }> ⟶ StlcArith.Tm.const (1 + n)
apply Step.succConst All goals completed! 🐙
| inr hs => succ.inr t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'hs:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ succ t₁ }> ⟶ t'
obtain ⟨t₁', hst⟩ := hs succ.inr t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmhst:t₁ ⟶ t₁'⊢ ∃ t', <{ succ t₁ }> ⟶ t'
exists <{ succ ~t₁' }> succ.inr t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmhst:t₁ ⟶ t₁'⊢ <{ succ t₁ }> ⟶ <{ succ t₁' }>
apply Step.succ succ.inr t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'
assumption All goals completed! 🐙
| pred Γ t₁ h ih => pred t:Tmτ:TyΓ✝:ContextΓ:Contextt₁:Tmh:<{ ~(Γ) ⊢ ~(t₁) ⦂ Nat }>ih:∅ = Γ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'hΓ:∅ = Γ⊢ <{ pred t₁ }>.IsValue ∨ ∃ t', <{ pred t₁ }> ⟶ t'
right pred t:Tmτ:TyΓ✝:ContextΓ:Contextt₁:Tmh:<{ ~(Γ) ⊢ ~(t₁) ⦂ Nat }>ih:∅ = Γ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'hΓ:∅ = Γ⊢ ∃ t', <{ pred t₁ }> ⟶ t'
subst hΓ pred t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'⊢ ∃ t', <{ pred t₁ }> ⟶ t'
cases ih rfl with
| inl hv => pred.inl t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'hv:t₁.IsValue⊢ ∃ t', <{ pred t₁ }> ⟶ t'
cases hv with
| abs => pred.inl.abs t:Tmτ:TyΓ:Contextx✝:Stringτ₂✝:Tyt₁✝:Tmh:<{ ∅ ⊢ λ ~x✝ : τ₂✝ . t₁✝ ⦂ Nat }>ih:∅ = ∅ → <{ λ ~x✝ : τ₂✝ . t₁✝ }>.IsValue ∨ ∃ t', <{ λ ~x✝ : τ₂✝ . t₁✝ }> ⟶ t'⊢ ∃ t', <{ pred (λ ~x✝ : τ₂✝ . t₁✝) }> ⟶ t' cases h All goals completed! 🐙
| const n => pred.inl.const t:Tmτ:TyΓ:Contextn:Nath:<{ ∅ ⊢ ~(StlcArith.Tm.const n) ⦂ Nat }>ih:∅ = ∅ → (StlcArith.Tm.const n).IsValue ∨ ∃ t', StlcArith.Tm.const n ⟶ t'⊢ ∃ t', <{ pred ~(StlcArith.Tm.const n) }> ⟶ t'
exists .const (n - 1) pred.inl.const t:Tmτ:TyΓ:Contextn:Nath:<{ ∅ ⊢ ~(StlcArith.Tm.const n) ⦂ Nat }>ih:∅ = ∅ → (StlcArith.Tm.const n).IsValue ∨ ∃ t', StlcArith.Tm.const n ⟶ t'⊢ <{ pred ~(StlcArith.Tm.const n) }> ⟶ StlcArith.Tm.const (n - 1)
apply Step.predConst All goals completed! 🐙
| inr hs => pred.inr t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'hs:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ pred t₁ }> ⟶ t'
obtain ⟨t₁', hst⟩ := hs pred.inr t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmhst:t₁ ⟶ t₁'⊢ ∃ t', <{ pred t₁ }> ⟶ t'
exists <{ pred ~t₁' }> pred.inr t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmhst:t₁ ⟶ t₁'⊢ <{ pred t₁ }> ⟶ <{ pred t₁' }>
apply Step.pred pred.inr t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'
assumption All goals completed! 🐙
| mult Γ t₁ t₂ h₁ h₂ ih₁ ih₂ => mult t:Tmτ:TyΓ✝:ContextΓ:Contextt₁:Tmt₂:Tmh₁:<{ ~(Γ) ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ~(Γ) ⊢ ~(t₂) ⦂ Nat }>ih₁:∅ = Γ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = Γ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hΓ:∅ = Γ⊢ <{ t₁ * t₂ }>.IsValue ∨ ∃ t', <{ t₁ * t₂ }> ⟶ t'
right mult t:Tmτ:TyΓ✝:ContextΓ: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'
subst hΓ 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 with
| inl hv₁ => 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'hv₁:t₁.IsValue⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
cases ih₂ rfl with
| inl hv₂ => mult.inl.inl t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuehv₂:t₂.IsValue⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
cases hv₁ with
| abs => mult.inl.inl.abs t:Tmτ:TyΓ:Contextt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₂:t₂.IsValuex✝:Stringτ₂✝:Tyt₁✝:Tmh₁:<{ ∅ ⊢ λ ~x✝ : τ₂✝ . t₁✝ ⦂ Nat }>ih₁:∅ = ∅ → <{ λ ~x✝ : τ₂✝ . t₁✝ }>.IsValue ∨ ∃ t', <{ λ ~x✝ : τ₂✝ . t₁✝ }> ⟶ t'⊢ ∃ t', <{ (λ ~x✝ : τ₂✝ . t₁✝) * t₂ }> ⟶ t' cases h₁ All goals completed! 🐙
| const n₁ => mult.inl.inl.const t:Tmτ:TyΓ:Contextt₂:Tmh₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₂:t₂.IsValuen₁:Nath₁:<{ ∅ ⊢ ~(StlcArith.Tm.const n₁) ⦂ Nat }>ih₁:∅ = ∅ → (StlcArith.Tm.const n₁).IsValue ∨ ∃ t', StlcArith.Tm.const n₁ ⟶ t'⊢ ∃ t', <{ ~(StlcArith.Tm.const n₁) * t₂ }> ⟶ t'
cases hv₂ with
| abs => mult.inl.inl.const.abs t:Tmτ:TyΓ:Contextn₁:Nath₁:<{ ∅ ⊢ ~(StlcArith.Tm.const n₁) ⦂ Nat }>ih₁:∅ = ∅ → (StlcArith.Tm.const n₁).IsValue ∨ ∃ t', StlcArith.Tm.const n₁ ⟶ t'x✝:Stringτ₂✝:Tyt₁✝:Tmh₂:<{ ∅ ⊢ λ ~x✝ : τ₂✝ . t₁✝ ⦂ Nat }>ih₂:∅ = ∅ → <{ λ ~x✝ : τ₂✝ . t₁✝ }>.IsValue ∨ ∃ t', <{ λ ~x✝ : τ₂✝ . t₁✝ }> ⟶ t'⊢ ∃ t', <{ ~(StlcArith.Tm.const n₁) * (λ ~x✝ : τ₂✝ . t₁✝) }> ⟶ t' cases h₂ All goals completed! 🐙
| const n₂ => mult.inl.inl.const.const t:Tmτ:TyΓ:Contextn₁:Nath₁:<{ ∅ ⊢ ~(StlcArith.Tm.const n₁) ⦂ Nat }>ih₁:∅ = ∅ → (StlcArith.Tm.const n₁).IsValue ∨ ∃ t', StlcArith.Tm.const n₁ ⟶ t'n₂:Nath₂:<{ ∅ ⊢ ~(StlcArith.Tm.const n₂) ⦂ Nat }>ih₂:∅ = ∅ → (StlcArith.Tm.const n₂).IsValue ∨ ∃ t', StlcArith.Tm.const n₂ ⟶ t'⊢ ∃ t', <{ ~(StlcArith.Tm.const n₁) * ~(StlcArith.Tm.const n₂) }> ⟶ t'
exists .const (n₁ * n₂) mult.inl.inl.const.const t:Tmτ:TyΓ:Contextn₁:Nath₁:<{ ∅ ⊢ ~(StlcArith.Tm.const n₁) ⦂ Nat }>ih₁:∅ = ∅ → (StlcArith.Tm.const n₁).IsValue ∨ ∃ t', StlcArith.Tm.const n₁ ⟶ t'n₂:Nath₂:<{ ∅ ⊢ ~(StlcArith.Tm.const n₂) ⦂ Nat }>ih₂:∅ = ∅ → (StlcArith.Tm.const n₂).IsValue ∨ ∃ t', StlcArith.Tm.const n₂ ⟶ t'⊢ <{ ~(StlcArith.Tm.const n₁) * ~(StlcArith.Tm.const n₂) }> ⟶ StlcArith.Tm.const (n₁ * n₂)
apply Step.multConst All goals completed! 🐙
| inr hs₂ => mult.inl.inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuehs₂:∃ t', t₂ ⟶ t'⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
obtain ⟨t₂', hst⟩ := hs₂ mult.inl.inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmhst:t₂ ⟶ t₂'⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
exists <{ ~t₁ * ~t₂' }> mult.inl.inr t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmhst:t₂ ⟶ t₂'⊢ <{ t₁ * t₂ }> ⟶ <{ t₁ * t₂' }>
apply Step.mult2 mult.inl.inr.hv t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmhst:t₂ ⟶ t₂'⊢ t₁.IsValuemult.inl.inr.h t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmhst:t₂ ⟶ t₂'⊢ t₂ ⟶ t₂' <;> mult.inl.inr.hv t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmhst:t₂ ⟶ t₂'⊢ t₁.IsValuemult.inl.inr.h t:Tmτ:TyΓ:Contextt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ Nat }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmhst:t₂ ⟶ t₂'⊢ t₂ ⟶ t₂' assumption All goals completed! 🐙
| inr hs₁ => 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'hs₁:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
obtain ⟨t₁', hst⟩ := hs₁ 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't₁':Tmhst:t₁ ⟶ t₁'⊢ ∃ t', <{ t₁ * t₂ }> ⟶ t'
exists <{ ~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't₁':Tmhst:t₁ ⟶ t₁'⊢ <{ t₁ * t₂ }> ⟶ <{ t₁' * t₂ }>
apply Step.mult1 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't₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'
assumption All goals completed! 🐙
| ite0 Γ t₁ t₂ t₃ τ₀ h₁ h₂ h₃ ih₁ ih₂ ih₃ => ite0 t:Tmτ:TyΓ✝:ContextΓ: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Γ:∅ = Γ⊢ <{ if0 t₁ then t₂ else t₃ }>.IsValue ∨ ∃ t', <{ if0 t₁ then t₂ else t₃ }> ⟶ t'
right ite0 t:Tmτ:TyΓ✝:ContextΓ: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', <{ if0 t₁ then t₂ else t₃ }> ⟶ t'
subst hΓ 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 with
| inl hv₁ => 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'hv₁:t₁.IsValue⊢ ∃ t', <{ if0 t₁ then t₂ else t₃ }> ⟶ t'
cases hv₁ with
| abs => ite0.inl.abs t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmτ₀:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₀) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₀) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'x✝:Stringτ₂✝:Tyt₁✝:Tmh₁:<{ ∅ ⊢ λ ~x✝ : τ₂✝ . t₁✝ ⦂ Nat }>ih₁:∅ = ∅ → <{ λ ~x✝ : τ₂✝ . t₁✝ }>.IsValue ∨ ∃ t', <{ λ ~x✝ : τ₂✝ . t₁✝ }> ⟶ t'⊢ ∃ t', <{ if0 (λ ~x✝ : τ₂✝ . t₁✝) then t₂ else t₃ }> ⟶ t' cases h₁ All goals completed! 🐙
| const n => ite0.inl.const t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmτ₀:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₀) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₀) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'n:Nath₁:<{ ∅ ⊢ ~(StlcArith.Tm.const n) ⦂ Nat }>ih₁:∅ = ∅ → (StlcArith.Tm.const n).IsValue ∨ ∃ t', StlcArith.Tm.const n ⟶ t'⊢ ∃ t', <{ if0 ~(StlcArith.Tm.const n) then t₂ else t₃ }> ⟶ t'
cases n with
| zero => ite0.inl.const.zero t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmτ₀:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₀) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₀) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'h₁:<{ ∅ ⊢ 0 ⦂ Nat }>ih₁:∅ = ∅ → <{ 0 }>.IsValue ∨ ∃ t', <{ 0 }> ⟶ t'⊢ ∃ t', <{ if0 0 then t₂ else t₃ }> ⟶ t'
exists t₂ ite0.inl.const.zero t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmτ₀:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₀) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₀) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'h₁:<{ ∅ ⊢ 0 ⦂ Nat }>ih₁:∅ = ∅ → <{ 0 }>.IsValue ∨ ∃ t', <{ 0 }> ⟶ t'⊢ <{ if0 0 then t₂ else t₃ }> ⟶ t₂
apply Step.if0Zero All goals completed! 🐙
| succ n' => ite0.inl.const.succ t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmτ₀:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₀) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₀) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'n':Nath₁:<{ ∅ ⊢ ~(StlcArith.Tm.const (n' + 1)) ⦂ Nat }>ih₁:∅ = ∅ → (StlcArith.Tm.const (n' + 1)).IsValue ∨ ∃ t', StlcArith.Tm.const (n' + 1) ⟶ t'⊢ ∃ t', <{ if0 ~(StlcArith.Tm.const (n' + 1)) then t₂ else t₃ }> ⟶ t'
exists t₃ ite0.inl.const.succ t:Tmτ:TyΓ:Contextt₂:Tmt₃:Tmτ₀:Tyh₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₀) }>h₃:<{ ∅ ⊢ ~(t₃) ⦂ ~(τ₀) }>ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'ih₃:∅ = ∅ → t₃.IsValue ∨ ∃ t', t₃ ⟶ t'n':Nath₁:<{ ∅ ⊢ ~(StlcArith.Tm.const (n' + 1)) ⦂ Nat }>ih₁:∅ = ∅ → (StlcArith.Tm.const (n' + 1)).IsValue ∨ ∃ t', StlcArith.Tm.const (n' + 1) ⟶ t'⊢ <{ if0 ~(StlcArith.Tm.const (n' + 1)) then t₂ else t₃ }> ⟶ t₃
apply Step.if0Nonzero All goals completed! 🐙
| inr hs₁ => 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'hs₁:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ if0 t₁ then t₂ else t₃ }> ⟶ t'
obtain ⟨t₁', hst⟩ := hs₁ 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't₁':Tmhst:t₁ ⟶ t₁'⊢ ∃ t', <{ if0 t₁ then t₂ else t₃ }> ⟶ t'
exists <{ if0 ~t₁' then ~t₂ else ~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't₁':Tmhst:t₁ ⟶ t₁'⊢ <{ if0 t₁ then t₂ else t₃ }> ⟶ <{ if0 t₁' then t₂ else t₃ }>
apply Step.if0Step 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't₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'
assumption All goals completed! 🐙
end StlcArith