Type Systems

6. StlcProp: Properties of STLC🔗

Note to developers (Benjamin Pierce @bcpierce00, before next release, 2022)

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, and HasType.abs cases are trivial, since in each of these cases we can see by inspecting the rule that t is a value.

  • If the last rule of the derivation is HasType.app, then t has the form t₁ t₂ for some t₁ and t₂, where ∅ ⊢ t₁ ⦂ τ₂ → τ and ∅ ⊢ t₂ ⦂ τ₂ for some type τ₂. The induction hypothesis for the first subderivation says that either t₁ is a value or else it can take a reduction step.

    • If t₁ is a value, then consider t₂, which by the induction hypothesis for the second subderivation must also either be a value or take a step.

      • Suppose t₂ is a value. Since t₁ is a value with an arrow type, it must be a lambda abstraction; hence t₁ t₂ can take a step by Step.appAbs.

      • Otherwise, t₂ can take a step, and hence so can t₁ t₂ by Step.app2.

    • If t₁ can take a step, then so can t₁ t₂ by Step.app1.

  • If the last rule of the derivation is HasType.ite, then t = if t₁ then t₂ else t₃, where t₁ has type Bool. The first IH says that t₁ either is a value or takes a step.

    • If t₁ is a value, then since it has type Bool it must be either true or false. If it is true, then t steps to t₂; otherwise it steps to t₃.

    • Otherwise, t₁ takes a step, and therefore so does t (by Step.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. t:Tmτ:TyΓ:Contextx:Stringτ₁:Tyh:none = some τ₁⊢ (Stlc.Tm.var x).IsValue ∨ ∃ t', Stlc.Tm.var x ⟶ t' All goals completed! 🐙 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' 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; All goals completed! 🐙 t:Tmτ:TyΓ:ContextΓ✝:ContexthΓ:∅ = Γ✝⊢ <{ true }>.IsValue ∨ ∃ t', <{ true }> ⟶ t' t:Tmτ:TyΓ:ContextΓ✝:ContexthΓ:∅ = Γ✝⊢ <{ true }>.IsValue; All goals completed! 🐙 t:Tmτ:TyΓ:ContextΓ✝:ContexthΓ:∅ = Γ✝⊢ <{ false }>.IsValue ∨ ∃ t', <{ false }> ⟶ t' t:Tmτ:TyΓ:ContextΓ✝:ContexthΓ:∅ = Γ✝⊢ <{ false }>.IsValue; All goals completed! 🐙 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. t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'⊢ <{ t₁ t₂ }>.IsValue ∨ ∃ t', <{ t₁ t₂ }> ⟶ t' t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t' cases ih₁ rfl with 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 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: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' 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 }> 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 All goals completed! 🐙 t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuehs₂:∃ t', t₂ ⟶ t'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t' t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t' t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ <{ t₁ t₂ }> ⟶ <{ t₁ t₂' }> t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ t₁.IsValuet: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: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₁.IsValuet: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₂' All goals completed! 🐙 t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hs₁:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t' t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t' t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ <{ t₁ t₂ }> ⟶ <{ t₁' t₂ }> t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁' t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁' All goals completed! 🐙 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' 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' 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 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 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' 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' 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₂ All goals completed! 🐙 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' 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' 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₃ All goals completed! 🐙 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' 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' 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₃ }> 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₁' All goals completed! 🐙
Exercise★★★(progress_from_term_ind) (Advanced)

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' := t:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ t.IsValue ∨ ∃ t', t ⟶ t' solution! induction t generalizing τ with x:Stringτ:Tyhτ:<{ ∅ ⊢ ~(Stlc.Tm.var x) ⦂ ~(τ) }>⊢ (Stlc.Tm.var x).IsValue ∨ ∃ t', Stlc.Tm.var x ⟶ t' cases hτ with x:Stringτ:Tyh:∅[x] = some τ⊢ (Stlc.Tm.var x).IsValue ∨ ∃ t', Stlc.Tm.var x ⟶ t' x:Stringτ:Tyh:none = some τ⊢ (Stlc.Tm.var x).IsValue ∨ ∃ t', Stlc.Tm.var x ⟶ t'; All goals completed! 🐙 x:Stringτ₂:Tyt₁:Tmt_ih✝:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'τ:Tyhτ:<{ ∅ ⊢ λ ~x : τ₂ . t₁ ⦂ ~(τ) }>⊢ <{ λ ~x : τ₂ . t₁ }>.IsValue ∨ ∃ t', <{ λ ~x : τ₂ . t₁ }> ⟶ t' x:Stringτ₂:Tyt₁:Tmt_ih✝:∀ (τ : Ty), <{ ∅ ⊢ ~(t₁) ⦂ ~(τ) }> → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'τ:Tyhτ:<{ ∅ ⊢ λ ~x : τ₂ . t₁ ⦂ ~(τ) }>⊢ <{ λ ~x : τ₂ . t₁ }>.IsValue All goals completed! 🐙 τ:Tyhτ:<{ ∅ ⊢ true ⦂ ~(τ) }>⊢ <{ true }>.IsValue ∨ ∃ t', <{ true }> ⟶ t' τ:Tyhτ:<{ ∅ ⊢ true ⦂ ~(τ) }>⊢ <{ true }>.IsValue All goals completed! 🐙 τ:Tyhτ:<{ ∅ ⊢ false ⦂ ~(τ) }>⊢ <{ false }>.IsValue ∨ ∃ t', <{ false }> ⟶ t' τ:Tyhτ:<{ ∅ ⊢ false ⦂ ~(τ) }>⊢ <{ false }>.IsValue All goals completed! 🐙 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' 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 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 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' 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 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' 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 }> 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 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 All goals completed! 🐙 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' 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' 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₂' }> 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 }>.IsValuet₂: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₂' 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 }>.IsValuet₂: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₂' All goals completed! 🐙 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' 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' 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₂ }> 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₁' All goals completed! 🐙 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' 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 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 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 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' 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' 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₂ All goals completed! 🐙 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' 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' 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₃ All goals completed! 🐙 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' 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' 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₃ }> 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₁' 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.appAbs rule, 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 s for a variable x in a term t preserves the type of t. The proof goes by induction on the form of t and 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 term s has type σ in the empty context the fact that s has 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 ⦂ ~τ }> := Γ:ContextΓ':Contextt:Tmτ:Tyhi:Γ ⊆ Γ'ht:<{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ~(Γ') ⊢ ~(t) ⦂ ~(τ) }> induction ht generalizing Γ' with Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:Tyh:Γ✝[x] = some T₁✝Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(Stlc.Tm.var x) ⦂ ~(T₁✝) }> Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:Tyh:Γ✝[x] = some T₁✝Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ'[x] = some T₁✝ All goals completed! 🐙 Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ {Γ' : Context}, x →ₚ T₂✝ ; Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ λ ~x : T₂✝ . t₁✝ ⦂ T₂✝ → T₁✝ }> Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ {Γ' : Context}, x →ₚ T₂✝ ; Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(x →ₚ T₂✝ ; Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }> Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ {Γ' : Context}, x →ₚ T₂✝ ; Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ x →ₚ T₂✝ ; Γ✝ ⊆ x →ₚ T₂✝ ; Γ' Γ:Contextt:Tmτ:TyΓ✝:Contextx:StringT₁✝:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>ih:∀ {Γ' : Context}, x →ₚ T₂✝ ; Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ' All goals completed! 🐙 Γ: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₁✝) }> Γ: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₁✝ }>Γ: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₂) }>Γ: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 Γ: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₁✝ }> Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ' All goals completed! 🐙 Γ: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₂✝) }> Γ:Contextt:Tmτ:TyΓ✝:ContextT₁✝:TyT₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>ih₁:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ T₂✝ → T₁✝ }>ih₂:∀ {Γ' : Context}, Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ' All goals completed! 🐙 Γ:Contextt:Tmτ:TyΓ✝:ContextΓ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ true ⦂ Bool }> All goals completed! 🐙 Γ:Contextt:Tmτ:TyΓ✝:ContextΓ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ false ⦂ Bool }> All goals completed! 🐙 Γ: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₁✝) }> Γ: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 }>Γ: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₁✝) }>Γ: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₁✝) }> Γ: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 }> Γ: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:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ' All goals completed! 🐙 Γ: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₁✝) }> Γ: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:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ' All goals completed! 🐙 Γ: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₁✝) }> Γ: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:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ' 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 ⦂ ~τ }> := Γ:ContextΓ':Contextt:Tmτ:Tyhi:Γ ⊆ Γ'ht:<{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ~(Γ') ⊢ ~(t) ⦂ ~(τ) }> induction ht generalizing Γ' with (All goals completed! 🐙)

The following simple corollary is what we actually need below.

theorem weakening_empty {Γ : Context} {t : Tm} {τ : Ty} (ht : <{ ∅ ⊢ ~t ⦂ ~τ }>) : <{ ~Γ ⊢ ~t ⦂ ~τ }> := Γ:Contextt:Tmτ:Tyht:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }> Γ:Contextt:Tmτ:Tyht:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ ∅ ⊆ ΓΓ: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. Γ:Contextt:Tmτ:Tyht:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ ∅ ⊆ Γ Γ:Contextt:Tmτ:Tyht:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>x:Stringb:Tycontra:∅[x] = some b⊢ Γ[x] = some b All goals completed! 🐙 Γ:Contextt:Tmτ:Tyht:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ∅ ⊢ ~(t) ⦂ ~(τ) }> 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 ⦂ ~τ }> := Γ: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 x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(Stlc.Tm.var y) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ) }> cases hτ with x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τ⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τhxy:x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ) }>x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τhxy:x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[x] = some τ⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var x) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τ⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var x) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τ⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τhτ'τ:τ' = τ⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contexth:some τ' = some τ'⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ') }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contexth:some τ' = some τ'⊢ <{ ∅ ⊢ ~(v) ⦂ ~(τ') }> All goals completed! 🐙 x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ ~(Stlc.Tm.var y) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τhxy:¬x = y⊢ Γ[y] = some τ All goals completed! 🐙 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 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₂) ⦂ ~(τ) }> 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₂ ⦂ ~(τ) }> 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₂ → τ }>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₂) }>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 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₂ → τ }> 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₂ → τ }> All goals completed! 🐙 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₂✝) }> 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₂✝) }> All goals completed! 🐙 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 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₁✝ }> 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₁✝ }>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₁✝ }> 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₁✝ }> 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₁✝ }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(x →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>⊢ <{ ~(Γ) ⊢ λ ~x : σ . t₁ ⦂ σ → T₁✝ }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(x →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>⊢ <{ ~(Γ) ⊢ λ ~x : σ . t₁ ⦂ σ → T₁✝ }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:ContextT₁✝:Tyh:<{ ~(x →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }>⊢ <{ ~(x →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(T₁✝) }> All goals completed! 🐙 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₁✝ }> 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₁✝ }> 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₁✝ }> 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₁✝) }> 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₁✝) }> All goals completed! 🐙 x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ true ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] true ⦂ ~(τ) }> cases hτ with x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Context⊢ <{ ~(Γ) ⊢ [~x := v] true ⦂ Bool }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Context⊢ <{ ~(Γ) ⊢ true ⦂ Bool }> All goals completed! 🐙 x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ false ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] false ⦂ ~(τ) }> cases hτ with x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Context⊢ <{ ~(Γ) ⊢ [~x := v] false ⦂ Bool }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Context⊢ <{ ~(Γ) ⊢ false ⦂ Bool }> All goals completed! 🐙 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 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) ⦂ ~(τ) }> 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 ⦂ ~(τ) }> 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 }>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 ⦂ ~(τ) }>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 ⦂ ~(τ) }> 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 }> 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 }> All goals completed! 🐙 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 ⦂ ~(τ) }> 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) ⦂ ~(τ) }> All goals completed! 🐙 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 ⦂ ~(τ) }> 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) ⦂ ~(τ) }> 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 t is a variable there are two cases to consider, depending on whether t is x or some other variable.

    • If t = x, then from the fact that x ↦ τ' ; Γ ⊢ x ⦂ τ we conclude that τ' = τ. We must show that [x:=v]x = v has type τ under Γ, given the assumption that v has type τ' = τ under the empty context. This follows from the weakening lemma.

    • If t is some variable y that is not equal to x, then we need only note that y has the same type under x ↦ τ' ; Γ as under Γ.

  • If t is an abstraction λy:σ. t₀, then τ = σ → τ₁ and the IH tells us, for all Γ' and τ₀, that if x ↦ τ' ; Γ' ⊢ t₀ ⦂ τ₀, then Γ' ⊢ [x:=v]t₀ ⦂ τ₀. Moreover, by inspecting the typing rules we see it must be the case that y ↦ σ ; x ↦ τ' ; Γ ⊢ t₀ ⦂ τ₁.

    The substitution in the conclusion behaves differently depending on whether x and y are the same variable.

    First, suppose x = y. Then, by the definition of substitution, [x:=v]t = t, so we just need to show Γ ⊢ t ⦂ τ. Using HasType.abs, we need to show that y ↦ σ ; Γ ⊢ t₀ ⦂ τ₁. But we know y ↦ σ ; x ↦ τ' ; Γ ⊢ t₀ ⦂ τ₁, and the claim follows since x = y.

    Second, suppose x ≠ y. Again, using HasType.abs, we need to show that y ↦ σ ; Γ ⊢ [x:=v]t₀ ⦂ τ₁. Since x ≠ y, we have y ↦ σ ; x ↦ τ' ; Γ = x ↦ τ' ; y ↦ σ ; Γ. So we have x ↦ τ' ; y ↦ σ ; Γ ⊢ t₀ ⦂ τ₁. Then, the IH applies (taking Γ' = y ↦ σ ; Γ), giving us y ↦ σ ; Γ ⊢ [x:=v]t₀ ⦂ τ₁, as required.

  • If t is an application t₁ 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!)

Exercise★★★(substitution_preserves_typing_from_typing_ind) (Advanced)

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 ⦂ ~τ }> := Γ:Contextx:Stringτ':Tyt:Tmv:Tmτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>hv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>⊢ <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }> solution! Γ:Contextx:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyhΓ:x →ₚ τ' ; Γ = Γ₀hτ:<{ ~(Γ₀) ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }> induction hτ generalizing Γ with x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:Contexty:Stringτ₁:Tyh:Γ✝[y] = some τ₁Γ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ₁) }> x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:Stringτ₁:TyΓ:Contexth:(x →ₚ τ' ; Γ)[y] = some τ₁⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ₁) }> 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) ⦂ ~(τ₁) }>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) ⦂ ~(τ₁) }> 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) ⦂ ~(τ₁) }> x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyτ₁:TyΓ:Contexth:(x →ₚ τ' ; Γ)[x] = some τ₁⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var x) ⦂ ~(τ₁) }> x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyτ₁:TyΓ:Contexth:some τ' = some τ₁⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var x) ⦂ ~(τ₁) }> x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyτ₁:TyΓ:Contexth:some τ' = some τ₁⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ₁) }> x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyτ₁:TyΓ:Contexth:some τ' = some τ₁hτ'τ:τ' = τ₁⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ₁) }> x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ:Contexth:some τ' = some τ'⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ') }> x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ:Contexth:some τ' = some τ'⊢ <{ ∅ ⊢ ~(v) ⦂ ~(τ') }> All goals completed! 🐙 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) ⦂ ~(τ₁) }> x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:Stringτ₁:TyΓ:Contexth:Γ[y] = some τ₁hxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(Stlc.Tm.var y) ⦂ ~(τ₁) }> x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:Stringτ₁:TyΓ:Contexth:Γ[y] = some τ₁hxy:¬x = y⊢ <{ ~(Γ) ⊢ ~(Stlc.Tm.var y) ⦂ ~(τ₁) }> x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String Tyy:Stringτ₁:TyΓ:Contexth:Γ[y] = some τ₁hxy:¬x = y⊢ Γ[y] = some τ₁ All goals completed! 🐙 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₁✝ }> 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₁✝ }> 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₁✝ }>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₁✝ }> 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₁✝ }> 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₁✝ }> 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₁✝ }> 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₁✝ }> 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₁✝) }> All goals completed! 🐙 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₁✝ }> 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₁✝ }> 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₁✝) }> 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 →ₚ τ' ; Γ 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 All goals completed! 🐙 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₁✝) }> 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₁✝) }> 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₁✝ }>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₂) }>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 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₁✝ }> 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 →ₚ τ' ; Γ = Γ✝ All goals completed! 🐙 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₂✝) }> 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 →ₚ τ' ; Γ = Γ✝ All goals completed! 🐙 x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextΓ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] true ⦂ Bool }> x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextΓ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ true ⦂ Bool }> All goals completed! 🐙 x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextΓ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ [~x := v] false ⦂ Bool }> x:Stringτ':Tyt:Tmv:Tmτ:Tyhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ₀:PartialMap String TyΓ✝:ContextΓ:ContexthΓ:x →ₚ τ' ; Γ = Γ✝⊢ <{ ~(Γ) ⊢ false ⦂ Bool }> All goals completed! 🐙 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₁✝) }> 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₁✝) }> 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 }>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₁✝) }>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₁✝) }> 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 }> 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 →ₚ τ' ; Γ = Γ✝ All goals completed! 🐙 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₁✝) }> 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 →ₚ τ' ; Γ = Γ✝ All goals completed! 🐙 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₁✝) }> 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 →ₚ τ' ; Γ = Γ✝ 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' ⦂ ~τ }> := t:Tmt':Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>hs:t ⟶ t'⊢ <{ ∅ ⊢ ~(t') ⦂ ~(τ) }> t:Tmt':Tmτ:Tyhs:t ⟶ t'Γ:ContexthΓ:∅ = Γhτ:<{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ ~(t') ⦂ ~(τ) }> induction hτ generalizing t' with t:Tmτ:TyΓ:ContextΓ✝:Contextx✝:StringT₁✝:Tyh✝:Γ✝[x✝] = some T₁✝t':Tmhs:Stlc.Tm.var x✝ ⟶ t'hΓ:∅ = Γ✝⊢ <{ ~(Γ✝) ⊢ ~(t') ⦂ ~(T₁✝) }> All goals completed! 🐙 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₁✝ }> All goals completed! 🐙 t:Tmτ:TyΓ:ContextΓ✝:Contextt':Tmhs:<{ true }> ⟶ t'hΓ:∅ = Γ✝⊢ <{ ~(Γ✝) ⊢ ~(t') ⦂ Bool }> All goals completed! 🐙 t:Tmτ:TyΓ:ContextΓ✝:Contextt':Tmhs:<{ false }> ⟶ t'hΓ:∅ = Γ✝⊢ <{ ~(Γ✝) ⊢ ~(t') ⦂ Bool }> All goals completed! 🐙 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') ⦂ ~(τ₁) }> 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 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 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✝ ⦂ ~(τ₁) }> 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✝) ⦂ ~(τ₁) }>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.τ') }>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 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✝) ⦂ ~(τ₁) }> All goals completed! 🐙 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₂) ⦂ ~(τ₂) }> All goals completed! 🐙 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₂ ⦂ ~(τ₁) }> 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₂ → τ₁ }>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₂) }>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 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₂ → τ₁ }> 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₁'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: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₁' All goals completed! 🐙 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₁'⊢ ∅ = ∅ All goals completed! 🐙 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₂) ⦂ ~(τ₂) }> All goals completed! 🐙 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₂' ⦂ ~(τ₁) }> 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₂ → τ₁ }>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₂) }>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 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₂ → τ₁ }> All goals completed! 🐙 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: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₂'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: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₂' All goals completed! 🐙 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₂'⊢ ∅ = ∅ All goals completed! 🐙 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') ⦂ ~(τ₁) }> 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 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₂) ⦂ ~(τ₁) }> All goals completed! 🐙 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₃) ⦂ ~(τ₁) }> All goals completed! 🐙 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₃ ⦂ ~(τ₁) }> 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 }>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: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: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 }> 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₁'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: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₁' All goals completed! 🐙 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₁'⊢ ∅ = ∅ All goals completed! 🐙 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₂) ⦂ ~(τ₁) }> All goals completed! 🐙 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₃) ⦂ ~(τ₁) }> All goals completed! 🐙

Proof: By induction on the derivation of ∅ ⊢ t ⦂ τ.

  • We can immediately rule out HasType.var, HasType.abs, HasType.tru, and HasType.fls as final rules in the derivation, since in each of these cases t cannot take a step.

  • If the last rule in the derivation is HasType.app, then t = 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 that t₁ t₂ takes a step to t'.

    • If t₁ t₂ takes a step by Step.app1, with t₁ stepping to t₁', then, by the first IH, t₁' has the same type as t₁ (∅ ⊢ t₁' ⦂ τ₂ → τ), and hence by HasType.app t₁' t₂ has type τ.

    • The Step.app2 case is similar, using the second IH.

    • If t₁ t₂ takes a step by Step.appAbs, then t₁ = λx:τ₀. t₀ and t₁ 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, then t = 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 t steps.

    • If t steps to t₂ or t₃ by Step.ifTrue or Step.ifFalse, the result is immediate, since t₂ and t₃ have the same type as t.

    • Otherwise, t steps by Step.ifStep, and the desired conclusion follows directly from the first induction hypothesis.

Exercise★★(subject_expansion_stlc) (Manually graded)

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.

Note to developers (Roger Burtonpatel @rogerburtonpatel)

This solution has to be rewritten; it is unreadable.

theorem not_subject_expansion : ∃ (t t' : Tm) (τ : Ty), t ⟶ t' ∧ <{ ∅ ⊢ ~t' ⦂ ~τ }> ∧ ¬ <{ ∅ ⊢ ~t ⦂ ~τ }> := ⊢ ∃ 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!( ⊢ <{ (λ x : Bool → Bool . true) true }> ⟶ <{ true }> ∧ <{ ∅ ⊢ true ⦂ Bool }> ∧ ¬<{ ∅ ⊢ (λ x : Bool → Bool . true) true ⦂ Bool }> ⊢ <{ (λ x : Bool → Bool . true) true }> ⟶ <{ true }>⊢ <{ ∅ ⊢ true ⦂ Bool }> ∧ ¬<{ ∅ ⊢ (λ x : Bool → Bool . true) true ⦂ Bool }> ⊢ <{ (λ x : Bool → Bool . true) true }> ⟶ <{ true }> ⊢ <{ true }>.IsValue; All goals completed! 🐙 ⊢ <{ ∅ ⊢ true ⦂ Bool }> ∧ ¬<{ ∅ ⊢ (λ x : Bool → Bool . true) true ⦂ Bool }> ⊢ <{ ∅ ⊢ true ⦂ Bool }>⊢ ¬<{ ∅ ⊢ (λ x : Bool → Bool . true) true ⦂ Bool }> ⊢ <{ ∅ ⊢ true ⦂ Bool }> All goals completed! 🐙 ⊢ ¬<{ ∅ ⊢ (λ x : Bool → Bool . true) true ⦂ Bool }> contra:<{ ∅ ⊢ (λ x : Bool → Bool . true) true ⦂ Bool }>⊢ False inversion contra with | app τ h₁ h₂ => h₁:<{ ∅ ⊢ true ⦂ Bool → Bool }>h✝:<{ x ↦ Bool → Bool ; ∅ ⊢ true ⦂ Bool }>⊢ False h₁:<{ ∅ ⊢ true ⦂ Bool → Bool }>h✝:<{ x ↦ Bool → Bool ; ∅ ⊢ true ⦂ Bool }>⊢ False All goals completed! 🐙 )

Alternative formulation.

6.4. Type Soundness🔗

Exercise★★(type_soundness) (Optional)

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 := t:Tmt':Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>hm:t ⟶* t'⊢ ¬t'.IsStuck t:Tmt':Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>hm:t ⟶* t'hst:t'.IsStuck⊢ False t:Tmt':Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>hm:t ⟶* t'hnf:IsNormalForm Step t'hnv:¬t'.IsValue⊢ False induction hm with t:Tmt':Tmτ:Tyu:Tmhτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step uhnv:¬u.IsValue⊢ False solution! cases progress u τ hτ with t:Tmt':Tmτ:Tyu:Tmhτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step uhnv:¬u.IsValuehv:u.IsValue⊢ False All goals completed! 🐙 t:Tmt':Tmτ:Tyu:Tmhτ:<{ ∅ ⊢ ~(u) ⦂ ~(τ) }>hnf:IsNormalForm Step uhnv:¬u.IsValuehs:∃ t', u ⟶ t'⊢ False All goals completed! 🐙 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! 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) ⦂ ~(τ) }>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 zt: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 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) ⦂ ~(τ) }> 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) ⦂ ~(τ) }>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 ⟶ wt: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 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) ⦂ ~(τ) }> All goals completed! 🐙 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 All goals completed! 🐙 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 All goals completed! 🐙 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 All goals completed! 🐙

6.5. Uniqueness of Types🔗

Exercise★★★(unique_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 ⦂ ~τ' }>) : τ = τ' := Γ:Contexte:Tmτ:Tyτ':Tyh:<{ ~(Γ) ⊢ ~(e) ⦂ ~(τ) }>h':<{ ~(Γ) ⊢ ~(e) ⦂ ~(τ') }>⊢ τ = τ' solution! induction h generalizing τ' with Γ:Contexte:Tmτ:TyΓ✝:Contextx✝:StringT₁✝:Tyhx:Γ✝[x✝] = some T₁✝τ':Tyh':<{ ~(Γ✝) ⊢ ~(Stlc.Tm.var x✝) ⦂ ~(τ') }>⊢ T₁✝ = τ' cases h' with Γ:Contexte:Tmτ:TyΓ✝:Contextx✝:StringT₁✝:Tyhx:Γ✝[x✝] = some T₁✝τ':Tyhx':Γ✝[x✝] = some τ'⊢ T₁✝ = τ' Γ:Contexte:Tmτ:TyΓ✝:Contextx✝:StringT₁✝:Tyhx:Γ✝[x✝] = some T₁✝τ':Tyhx':some T₁✝ = some τ'⊢ T₁✝ = τ' All goals completed! 🐙 Γ:Contexte:Tmτ:TyΓ✝:Contextx✝:Stringτ₁:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁) }>ih:∀ (τ' : Ty), <{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ') }> → τ₁ = τ'τ':Tyh':<{ ~(Γ✝) ⊢ λ ~x✝ : T₂✝ . t₁✝ ⦂ ~(τ') }>⊢ <{ T₂✝ → τ₁ }> = τ' cases h' with Γ:Contexte:Tmτ:TyΓ✝:Contextx✝:Stringτ₁:TyT₂✝:Tyt₁✝:Tmh✝:<{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁) }>ih:∀ (τ' : Ty), <{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ') }> → τ₁ = τ'τ₁':Tyhb':<{ ~(x✝ →ₚ T₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁') }>⊢ <{ T₂✝ → τ₁ }> = <{ T₂✝ → τ₁' }> Γ: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! 🐙 Γ: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 Γ: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₁✝ = τ' Γ: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₁✝ = τ' All goals completed! 🐙 Γ:Contexte:Tmτ:TyΓ✝:Contextτ':Tyh':<{ ~(Γ✝) ⊢ true ⦂ ~(τ') }>⊢ <{ Bool }> = τ' cases h' with Γ:Contexte:Tmτ:TyΓ✝:Context⊢ <{ Bool }> = <{ Bool }> All goals completed! 🐙 Γ:Contexte:Tmτ:TyΓ✝:Contextτ':Tyh':<{ ~(Γ✝) ⊢ false ⦂ ~(τ') }>⊢ <{ Bool }> = τ' cases h' with Γ:Contexte:Tmτ:TyΓ✝:Context⊢ <{ Bool }> = <{ Bool }> All goals completed! 🐙 Γ: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 Γ: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₁✝ = τ' Γ: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₂✝) ⦂ ~(τ') }> 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:

  • y appears free, but x does not, in λx:τ → τ'. x y

  • both x and y appear 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.")

Exercise★(afi) (Optional, Manually graded)

(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, then t = x, and from the assumption that t is well typed under Γ we have immediately that Γ assigns a type to x.

  • If the last rule used is AppearsFreeIn.app1, then t = t₁ t₂ and x appears free in t₁. Since t is well typed under Γ, we can see from the typing rules that t₁ must also be, and the IH then tells us that Γ assigns x a type.

  • Almost all the other cases are similar: x appears free in a subterm of t, and since t is well typed under Γ, we know the subterm of t in which x appears 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 case t = λy:τ₁. t₁ and x appears free in t₁, and we also know that x is different from y. The difference from the previous cases is that, whereas t is well typed under Γ, its body t₁ is well typed under y ↦ τ₁ ; Γ, so the IH allows us to conclude that x is assigned some type by the extended context y ↦ τ₁ ; Γ. To conclude that Γ assigns a type to x, we appeal to lemma PartialMap.update_neq, noting that x and y are different variables.

Exercise★★(free_in_context)

Complete the following proof.

theorem free_in_context (x : String) (t : Tm) (τ : Ty) (Γ : Context) (ha : x ∈ᶠ t) (hτ : <{ ~Γ ⊢ ~t ⦂ ~τ }>) : ∃ τ', Γ[x] = some τ' := x:Stringt:Tmτ:TyΓ:Contextha:x ∈ᶠ thτ:<{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ' induction ha generalizing Γ τ with x:Stringt:Tmτ:TyΓ:Contexthτ:<{ ~(Γ) ⊢ ~(Stlc.Tm.var x) ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ' cases hτ with x:Stringt:Tmτ:TyΓ:Contexth:Γ[x] = some τ⊢ ∃ τ', Γ[x] = some τ' x:Stringt:Tmτ:TyΓ:Contexth:Γ[x] = some τ⊢ Γ[x] = some ?var.var.wx:Stringt:Tmτ:TyΓ:Contexth:Γ[x] = some τ⊢ Ty All goals completed! 🐙 x:Stringt:Tmt₁✝:Tmt₂✝:Tmh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexthτ:<{ ~(Γ) ⊢ t₁✝ t₂✝ ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ' cases hτ with x:Stringt:Tmt₁✝:Tmt₂✝:Tmh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:ContextT₂✝:Tyh₂✝:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>h₁:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ T₂✝ → τ }>⊢ ∃ τ', Γ[x] = some τ' x:Stringt:Tmt₁✝:Tmt₂✝:Tmh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:ContextT₂✝:Tyh₂✝:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>h₁:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ T₂✝ → τ }>⊢ <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(?app1.app.τ) }>x:Stringt:Tmt₁✝:Tmt₂✝:Tmh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:ContextT₂✝:Tyh₂✝:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>h₁:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ T₂✝ → τ }>⊢ Ty All goals completed! 🐙 x:Stringt:Tmt₁✝:Tmt₂✝:Tmh✝:x ∈ᶠ t₂✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexthτ:<{ ~(Γ) ⊢ t₁✝ t₂✝ ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ' cases hτ with x:Stringt:Tmt₁✝:Tmt₂✝:Tmh✝:x ∈ᶠ t₂✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:ContextT₂✝:Tyh₂:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>h₁✝:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ T₂✝ → τ }>⊢ ∃ τ', Γ[x] = some τ' x:Stringt:Tmt₁✝:Tmt₂✝:Tmh✝:x ∈ᶠ t₂✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:ContextT₂✝:Tyh₂:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>h₁✝:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ T₂✝ → τ }>⊢ <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(?app2.app.τ) }>x:Stringt:Tmt₁✝:Tmt₂✝:Tmh✝:x ∈ᶠ t₂✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:ContextT₂✝:Tyh₂:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(T₂✝) }>h₁✝:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ T₂✝ → τ }>⊢ Ty All goals completed! 🐙 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 x:Stringt:Tmy:Stringτ₁✝:Tyt₁✝:Tmhne:y ≠ xh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'Γ:ContextT₁✝:Tyhb:<{ ~(y →ₚ τ₁✝ ; Γ) ⊢ ~(t₁✝) ⦂ ~(T₁✝) }>⊢ ∃ τ', Γ[x] = some τ' 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 τ' 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 τ' All goals completed! 🐙 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 x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexth₁:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }>h₃✝:<{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ' 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.τ) }>x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₁✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₁✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexth₁:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }>h₃✝:<{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }>⊢ Ty All goals completed! 🐙 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 x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₂✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexth₁✝:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ Bool }>h₂:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }>h₃✝:<{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ' 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.τ) }>x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₂✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexth₁✝:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ Bool }>h₂:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }>h₃✝:<{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }>⊢ Ty All goals completed! 🐙 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 x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₃✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexth₁✝:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }>h₃:<{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }>⊢ ∃ τ', Γ[x] = some τ' 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.τ) }>x:Stringt:Tmt₁✝:Tmt₂✝:Tmt₃✝:Tmh✝:x ∈ᶠ t₃✝ih:∀ (τ : Ty) (Γ : Context), <{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }> → ∃ τ', Γ[x] = some τ'τ:TyΓ:Contexth₁✝:<{ ~(Γ) ⊢ ~(t₁✝) ⦂ Bool }>h₂✝:<{ ~(Γ) ⊢ ~(t₂✝) ⦂ ~(τ) }>h₃:<{ ~(Γ) ⊢ ~(t₃✝) ⦂ ~(τ) }>⊢ Ty 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).

Exercise★★(typable_empty_closed) (Optional)
theorem typable_empty_closed (t : Tm) (τ : Ty) (hτ : <{ ∅ ⊢ ~t ⦂ ~τ }>) : t.Closed := t:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ t.Closed solution! t:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>x:Stringha:x ∈ᶠ t⊢ False t:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>x:Stringha:x ∈ᶠ tτ':Tyhc:∅[x] = some τ'⊢ False t:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>x:Stringha:x ∈ᶠ tτ':Tyhc:none = some τ'⊢ False 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, then t = x and Γ x = τ. By assumption, Γ' x = τ as well, and hence Γ' ⊢ t ⦂ τ by HasType.var.

  • If the last rule was HasType.abs, then t = λy:τ₂. t₁, with τ = τ₂ → τ₁ and y ↦ τ₂ ; Γ ⊢ t₁ ⦂ τ₁. The induction hypothesis states that for any context Γ'', if y ↦ τ₂ ; Γ and Γ'' assign the same types to all the free variables in t₁, then t₁ has type τ₁ under Γ''. Let Γ' be a context which agrees with Γ on the free variables in t; we must show Γ' ⊢ λy:τ₂. t₁ ⦂ τ₂ → τ₁.

    By HasType.abs, it suffices to show that y ↦ τ₂ ; Γ' ⊢ t₁ ⦂ τ₁. By the IH (setting Γ'' = y ↦ τ₂ ; Γ'), it suffices to show that y ↦ τ₂ ; Γ and y ↦ τ₂ ; Γ' agree on all the variables that appear free in t₁.

    Any variable occurring free in t₁ must be either y or some other variable. y ↦ τ₂ ; Γ and y ↦ τ₂ ; Γ' clearly agree on y. Otherwise, note that any variable other than y that occurs free in t₁ also occurs free in t = λy:τ₂. t₁, and by assumption Γ and Γ' agree on all such variables; hence so do y ↦ τ₂ ; Γ and y ↦ τ₂ ; Γ'.

  • If the last rule was HasType.app, then t = t₁ t₂, with Γ ⊢ t₁ ⦂ τ₂ → τ and Γ ⊢ t₂ ⦂ τ₂. One induction hypothesis states that for all contexts Γ', if Γ' agrees with Γ on the free variables in t₁, then t₁ has type τ₂ → τ under Γ'; there is a similar IH for t₂. We must show that t₁ t₂ also has type τ under Γ', given the assumption that Γ' agrees with Γ on all the free variables in t₁ t₂. By HasType.app, it suffices to show that t₁ and t₂ each have the same type under Γ' as under Γ. But all free variables in t₁ are also free in t₁ t₂, and similarly for t₂; hence the desired result follows from the induction hypotheses.

Exercise★★★(context_invariance) (Optional)

Complete the following proof.

theorem context_invariance (Γ Γ' : Context) (t : Tm) (τ : Ty) (hτ : <{ ~Γ ⊢ ~t ⦂ ~τ }>) (hf : ∀ x, x ∈ᶠ t → Γ[x] = Γ'[x]) : <{ ~Γ' ⊢ ~t ⦂ ~τ }> := Γ:ContextΓ':Contextt:Tmτ:Tyhτ:<{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>hf:∀ (x : String), x ∈ᶠ t → Γ[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ ~(t) ⦂ ~(τ) }> induction hτ generalizing Γ' with Γ: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! Γ: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₁✝ Γ: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] Γ: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] Γ: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 All goals completed! 🐙 Γ: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! Γ: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₁✝) }> Γ: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] Γ: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] Γ: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]Γ: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] Γ: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] Γ: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]; All goals completed! 🐙 -- The only tricky step. Γ: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] Γ: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] Γ: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₁✝ }> Γ: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 ≠ zΓ: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₁✝ Γ: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 ≠ zΓ: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₁✝ All goals completed! 🐙 Γ: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! Γ: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₁✝ }>Γ: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₂) }>Γ: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 Γ: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₁✝ }> Γ: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] Γ: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] Γ: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₂ }> Γ: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₁ All goals completed! 🐙 Γ: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₂✝) }> Γ: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] Γ: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] Γ: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₂ }> Γ: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₂ All goals completed! 🐙 Γ:Contextt:Tmτ:TyΓ✝:ContextΓ':Contexthf:∀ (x : String), x ∈ᶠ <{ true }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ true ⦂ Bool }> All goals completed! 🐙 Γ:Contextt:Tmτ:TyΓ✝:ContextΓ':Contexthf:∀ (x : String), x ∈ᶠ <{ false }> → Γ✝[x] = Γ'[x]⊢ <{ ~(Γ') ⊢ false ⦂ Bool }> All goals completed! 🐙 Γ: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₁✝) }> Γ: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 }>Γ: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₁✝) }>Γ: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₁✝) }> Γ: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 }> Γ: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] Γ: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] Γ: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₃ }> Γ: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₁ All goals completed! 🐙 Γ: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₁✝) }> Γ: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] Γ: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] Γ: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₃ }> Γ: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₂ All goals completed! 🐙 Γ: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₁✝) }> Γ: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] Γ: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] Γ: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₃ }> Γ: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₃ 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🔗

Exercise★(progress_preservation_statement) (Optional, Manually graded)

(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.

Note to developers (before next release)

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
Exercise★★(stlc_variation1) (Manually graded)

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.

Exercise★★(stlc_variation2) (Manually graded)

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.

Exercise★★(stlc_variation3) (Manually graded)

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.

Exercise★★(stlc_variation4) (Optional)

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.

Exercise★★(stlc_variation5) (Optional)

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

Exercise★★(stlc_variation6) (Optional)

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.

Exercise★★(stlc_variation7) (Optional)

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.

Exercise★★★★★(StlcArith.subst)

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 := x:Strings:Tm⊢ <{ [~x := s] ~(StlcArith.Tm.var x) }> = s All goals completed! 🐙 @[simp] theorem subst_var_ne (h : x ≠ y) : <{ [~x := ~s] ~(Tm.var y) }> = .var y := x:Stringy:Strings:Tmh:x ≠ y⊢ <{ [~x := s] ~(StlcArith.Tm.var y) }> = StlcArith.Tm.var y All goals completed! 🐙 @[simp] theorem subst_abs_eq : <{ [~x := ~s] (λ ~x : ~τ . ~t) }> = <{ λ ~x : ~τ . ~t }> := x:Strings:Tmt:Tmτ:Ty⊢ <{ [~x := s] (λ ~x : τ . t) }> = <{ λ ~x : τ . t }> All goals completed! 🐙 @[simp] theorem subst_abs_ne (h : x ≠ y) : <{ [~x := ~s] (λ ~y : ~τ . ~t) }> = <{ λ ~y : ~τ . [~x := ~s] ~t }> := x:Stringy:Strings:Tmt:Tmτ:Tyh:x ≠ y⊢ <{ [~x := s] (λ ~y : τ . t) }> = <{ λ ~y : τ . [~x := s] t }> 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 := ⊢ ∃ t, <{ (λ x : Nat . λ y : Nat . x * y) 3 2 }> ⟶* t solution! ⊢ <{ (λ x : Nat . λ y : Nat . x * y) 3 2 }> ⟶* <{ 6 }> All goals completed! 🐙
Note to developers (before next release)

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 }> := ⊢ <{ ∅ ⊢ (λ x : Nat . λ y : Nat . x * y) 3 2 ⦂ Nat }> solution! ⊢ <{ ∅ ⊢ (λ x : Nat . λ y : Nat . x * y) 3 ⦂ Nat → Nat }>⊢ <{ ∅ ⊢ 2 ⦂ Nat }> ⊢ <{ ∅ ⊢ (λ x : Nat . λ y : Nat . x * y) 3 ⦂ Nat → Nat }> ⊢ <{ ∅ ⊢ λ x : Nat . λ y : Nat . x * y ⦂ Nat → Nat → Nat }>⊢ <{ ∅ ⊢ 3 ⦂ Nat }> ⊢ <{ ∅ ⊢ λ x : Nat . λ y : Nat . x * y ⦂ Nat → Nat → Nat }> ⊢ <{ x ↦ Nat ; ∅ ⊢ λ y : Nat . x * y ⦂ Nat → Nat }> ⊢ <{ y ↦ Nat ; x ↦ Nat ; ∅ ⊢ x * y ⦂ Nat }> ⊢ <{ y ↦ Nat ; x ↦ Nat ; ∅ ⊢ x ⦂ Nat }>⊢ <{ y ↦ Nat ; x ↦ Nat ; ∅ ⊢ y ⦂ Nat }> ⊢ <{ y ↦ Nat ; x ↦ Nat ; ∅ ⊢ x ⦂ Nat }> ⊢ ("y" →ₚ <{ Nat }> ; "x" →ₚ <{ Nat }>)["x"] = some <{ Nat }> All goals completed! 🐙 ⊢ <{ y ↦ Nat ; x ↦ Nat ; ∅ ⊢ y ⦂ Nat }> ⊢ ("y" →ₚ <{ Nat }> ; "x" →ₚ <{ Nat }>)["y"] = some <{ Nat }> All goals completed! 🐙 ⊢ <{ ∅ ⊢ 3 ⦂ Nat }> All goals completed! 🐙 ⊢ <{ ∅ ⊢ 2 ⦂ Nat }> All goals completed! 🐙

6.7.1.1. The Technical Theorems🔗

The next lemmas are proved exactly as before.

Exercise★★★★(StlcArith.weakening)
theorem weakening (Γ Γ' : Context) (t : Tm) (τ : Ty) (hi : Γ ⊆ Γ') (hτ : <{ ~Γ ⊢ ~t ⦂ ~τ }>) : <{ ~Γ' ⊢ ~t ⦂ ~τ }> := Γ:ContextΓ':Contextt:Tmτ:Tyhi:Γ ⊆ Γ'hτ:<{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ~(Γ') ⊢ ~(t) ⦂ ~(τ) }> solution! induction hτ generalizing Γ' with Γ:Contextt:Tmτ:TyΓ✝:Contextx:Stringτ₁✝:Tyh:Γ✝[x] = some τ₁✝Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(StlcArith.Tm.var x) ⦂ ~(τ₁✝) }> Γ:Contextt:Tmτ:TyΓ✝:Contextx:Stringτ₁✝:Tyh:Γ✝[x] = some τ₁✝Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ'[x] = some τ₁✝ All goals completed! 🐙 Γ:Contextt:Tmτ:TyΓ✝:Contextx:Stringτ₁✝:Tyτ₂✝:Tyt₁✝:Tmh✝:<{ ~(x →ₚ τ₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>ih:∀ (Γ' : Context), x →ₚ τ₂✝ ; Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ λ ~x : τ₂✝ . t₁✝ ⦂ τ₂✝ → τ₁✝ }> Γ:Contextt:Tmτ:TyΓ✝:Contextx:Stringτ₁✝:Tyτ₂✝:Tyt₁✝:Tmh✝:<{ ~(x →ₚ τ₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>ih:∀ (Γ' : Context), x →ₚ τ₂✝ ; Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(x →ₚ τ₂✝ ; Γ') ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }> Γ:Contextt:Tmτ:TyΓ✝:Contextx:Stringτ₁✝:Tyτ₂✝:Tyt₁✝:Tmh✝:<{ ~(x →ₚ τ₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>ih:∀ (Γ' : Context), x →ₚ τ₂✝ ; Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ x →ₚ τ₂✝ ; Γ✝ ⊆ x →ₚ τ₂✝ ; Γ' Γ:Contextt:Tmτ:TyΓ✝:Contextx:Stringτ₁✝:Tyτ₂✝:Tyt₁✝:Tmh✝:<{ ~(x →ₚ τ₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>ih:∀ (Γ' : Context), x →ₚ τ₂✝ ; Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ' All goals completed! 🐙 Γ:Contextt:Tmτ:TyΓ✝:Contextτ₁✝:Tyτ₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ t₁✝ t₂✝ ⦂ ~(τ₁✝) }> Γ:Contextt:Tmτ:TyΓ✝:Contextτ₁✝:Tyτ₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~?app.τ₂ → τ₁✝ }>Γ:Contextt:Tmτ:TyΓ✝:Contextτ₁✝:Tyτ₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(?app.τ₂) }>Γ:Contextt:Tmτ:TyΓ✝:Contextτ₁✝:Tyτ₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Ty Γ:Contextt:Tmτ:TyΓ✝:Contextτ₁✝:Tyτ₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ ~?app.τ₂ → τ₁✝ }> Γ:Contextt:Tmτ:TyΓ✝:Contextτ₁✝:Tyτ₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ' All goals completed! 🐙 Γ:Contextt:Tmτ:TyΓ✝:Contextτ₁✝:Tyτ₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }> Γ:Contextt:Tmτ:TyΓ✝:Contextτ₁✝:Tyτ₂✝:Tyt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ τ₂✝ → τ₁✝ }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ ~(τ₂✝) }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ' All goals completed! 🐙 Γ:Contextt:Tmτ:TyΓ✝:Contextn:NatΓ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(StlcArith.Tm.const n) ⦂ Nat }> All goals completed! 🐙 Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmh✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>ih:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ succ t₁✝ ⦂ Nat }> Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmh✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>ih:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }> Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmh✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>ih:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ' All goals completed! 🐙 Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmh✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>ih:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ pred t₁✝ ⦂ Nat }> Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmh✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>ih:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }> Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmh✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>ih:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ' All goals completed! 🐙 Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ Nat }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ t₁✝ * t₂✝ ⦂ Nat }> Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ Nat }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ Nat }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }> Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ Nat }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }> Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ Nat }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ' All goals completed! 🐙 Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ Nat }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }> Γ:Contextt:Tmτ:TyΓ✝:Contextt₁✝:Tmt₂✝:Tmh₁✝:<{ ~(Γ✝) ⊢ ~(t₁✝) ⦂ Nat }>h₂✝:<{ ~(Γ✝) ⊢ ~(t₂✝) ⦂ Nat }>ih₁:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₁✝) ⦂ Nat }>ih₂:∀ (Γ' : Context), Γ✝ ⊆ Γ' → <{ ~(Γ') ⊢ ~(t₂✝) ⦂ Nat }>Γ':Contexthi:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ' All goals completed! 🐙 Γ: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₃✝ ⦂ ~(τ₀✝) }> Γ: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 }>Γ: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₂✝) ⦂ ~(τ₀✝) }>Γ: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₃✝) ⦂ ~(τ₀✝) }> Γ: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 }> Γ: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:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ' All goals completed! 🐙 Γ: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₂✝) ⦂ ~(τ₀✝) }> Γ: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:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ' All goals completed! 🐙 Γ: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₃✝) ⦂ ~(τ₀✝) }> Γ: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:Γ✝ ⊆ Γ'⊢ Γ✝ ⊆ Γ' 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 ⦂ ~τ }> := Γ:Contextt:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }> Γ:Contextt:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ ∅ ⊆ ΓΓ:Contextt:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ∅ ⊢ ~(t) ⦂ ~(τ) }> Γ:Contextt:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ ∅ ⊆ Γ Γ:Contextt:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>x:Stringb:Tycontra:∅[x] = some b⊢ Γ[x] = some b All goals completed! 🐙 Γ:Contextt:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ∅ ⊢ ~(t) ⦂ ~(τ) }> All goals completed! 🐙 theorem substitution_preserves_typing (Γ : Context) (x : String) (τ' : Ty) (t v : Tm) (τ : Ty) (hτ : <{ ~x ↦ ~τ' ; ~Γ ⊢ ~t ⦂ ~τ }>) (hv : <{ ∅ ⊢ ~v ⦂ ~τ' }>) : <{ ~Γ ⊢ [~x := ~v] ~t ⦂ ~τ }> := Γ:Contextx:Stringτ':Tyt:Tmv:Tmτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t) ⦂ ~(τ) }>hv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>⊢ <{ ~(Γ) ⊢ [~x := v] t ⦂ ~(τ) }> induction t generalizing Γ τ with x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(StlcArith.Tm.var y) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var y) ⦂ ~(τ) }> cases hτ with x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τ⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var y) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τhxy:x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var y) ⦂ ~(τ) }>x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var y) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τhxy:x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var y) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[x] = some τ⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var x) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τ⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var x) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τ⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contextτ:Tyh:some τ' = some τhτ'τ:τ' = τ⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contexth:some τ' = some τ'⊢ <{ ~(Γ) ⊢ ~(v) ⦂ ~(τ') }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>Γ:Contexth:some τ' = some τ'⊢ <{ ∅ ⊢ ~(v) ⦂ ~(τ') }> All goals completed! 🐙 x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:(x →ₚ τ' ; Γ)[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var y) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.var y) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τhxy:¬x = y⊢ <{ ~(Γ) ⊢ ~(StlcArith.Tm.var y) ⦂ ~(τ) }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>y:StringΓ:Contextτ:Tyh:Γ[y] = some τhxy:¬x = y⊢ Γ[y] = some τ All goals completed! 🐙 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 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₂) ⦂ ~(τ) }> 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₂ ⦂ ~(τ) }> 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.τ₂ → τ }>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.τ₂) }>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 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.τ₂ → τ }> 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.τ₂ → τ }> All goals completed! 🐙 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: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₂) ⦂ ~(τ₂✝) }> All goals completed! 🐙 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 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₁) ⦂ σ → τ₁✝ }> 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₁) ⦂ σ → τ₁✝ }>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₁) ⦂ σ → τ₁✝ }> 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₁) ⦂ σ → τ₁✝ }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>⊢ <{ ~(Γ) ⊢ [~x := v] (λ ~x : σ . t₁) ⦂ σ → τ₁✝ }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ σ ; x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>⊢ <{ ~(Γ) ⊢ λ ~x : σ . t₁ ⦂ σ → τ₁✝ }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>⊢ <{ ~(Γ) ⊢ λ ~x : σ . t₁ ⦂ σ → τ₁✝ }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>σ:Tyt₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contextτ₁✝:Tyh:<{ ~(x →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }>⊢ <{ ~(x →ₚ σ ; Γ) ⊢ ~(t₁) ⦂ ~(τ₁✝) }> All goals completed! 🐙 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₁) ⦂ σ → τ₁✝ }> 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₁ ⦂ σ → τ₁✝ }> 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₁ ⦂ σ → τ₁✝ }> 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₁ ⦂ ~(τ₁✝) }> 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₁) ⦂ ~(τ₁✝) }> All goals completed! 🐙 x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>n:NatΓ:Contextτ:Tyhτ:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(StlcArith.Tm.const n) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.const n) ⦂ ~(τ) }> cases hτ with x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>n:NatΓ:Context⊢ <{ ~(Γ) ⊢ [~x := v] ~(StlcArith.Tm.const n) ⦂ Nat }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>n:NatΓ:Context⊢ <{ ~(Γ) ⊢ ~(StlcArith.Tm.const n) ⦂ Nat }> All goals completed! 🐙 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 x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ [~x := v] (succ t₁) ⦂ Nat }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ succ [~x := v] t₁ ⦂ Nat }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ Nat }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }> All goals completed! 🐙 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 x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ [~x := v] (pred t₁) ⦂ Nat }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ pred [~x := v] t₁ ⦂ Nat }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ Nat }> x:Stringτ':Tyv:Tmhv:<{ ∅ ⊢ ~(v) ⦂ ~(τ') }>t₁:Tmih:∀ (Γ : Context) (τ : Ty), <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ ~(τ) }> → <{ ~(Γ) ⊢ [~x := v] t₁ ⦂ ~(τ) }>Γ:Contexth:<{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }>⊢ <{ ~(x →ₚ τ' ; Γ) ⊢ ~(t₁) ⦂ Nat }> All goals completed! 🐙 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 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 }> 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 }> 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 }>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 }> 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 }> 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 }> All goals completed! 🐙 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 }> 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 }> All goals completed! 🐙 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 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₃) ⦂ ~(τ) }> 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₃ ⦂ ~(τ) }> 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 }>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₂ ⦂ ~(τ) }>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₃ ⦂ ~(τ) }> 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 }> 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 }> All goals completed! 🐙 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₂ ⦂ ~(τ) }> 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₂) ⦂ ~(τ) }> All goals completed! 🐙 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₃ ⦂ ~(τ) }> 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₃) ⦂ ~(τ) }> All goals completed! 🐙

6.7.1.2. Preservation🔗

Exercise★★★★(StlcArith.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' ⦂ ~τ }> := t:Tmt':Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>hs:t ⟶ t'⊢ <{ ∅ ⊢ ~(t') ⦂ ~(τ) }> solution! t:Tmt':Tmτ:Tyhs:t ⟶ t'Γ:ContexthΓ:∅ = Γhτ:<{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>⊢ <{ ~(Γ) ⊢ ~(t') ⦂ ~(τ) }> induction hτ generalizing t' with t:Tmτ:TyΓ:ContextΓ✝:Contextx✝:Stringτ₁✝:Tyh✝:Γ✝[x✝] = some τ₁✝t':Tmhs:StlcArith.Tm.var x✝ ⟶ t'hΓ:∅ = Γ✝⊢ <{ ~(Γ✝) ⊢ ~(t') ⦂ ~(τ₁✝) }> All goals completed! 🐙 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') ⦂ τ₂✝ → τ₁✝ }> All goals completed! 🐙 t:Tmτ:TyΓ:ContextΓ✝:Contextn✝:Natt':Tmhs:StlcArith.Tm.const n✝ ⟶ t'hΓ:∅ = Γ✝⊢ <{ ~(Γ✝) ⊢ ~(t') ⦂ Nat }> All goals completed! 🐙 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') ⦂ ~(τ₁) }> 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 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 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✝ ⦂ ~(τ₁) }> 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✝) ⦂ ~(τ₁) }>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.τ') }>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 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✝) ⦂ ~(τ₁) }> All goals completed! 🐙 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₂) ⦂ ~(τ₂) }> All goals completed! 🐙 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₂ ⦂ ~(τ₁) }> 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: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: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 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: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₁'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: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₁' All goals completed! 🐙 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₁'⊢ ∅ = ∅ All goals completed! 🐙 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₂) ⦂ ~(τ₂) }> All goals completed! 🐙 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₂' ⦂ ~(τ₁) }> 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: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: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 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.τ₂ → τ₁ }> All goals completed! 🐙 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: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₂'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: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₂' All goals completed! 🐙 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₂'⊢ ∅ = ∅ All goals completed! 🐙 t:Tmτ:TyΓ✝:ContextΓ:Contextt₁:Tmh:<{ ~(Γ) ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = Γ → <{ ~(Γ) ⊢ ~(t') ⦂ Nat }>t':Tmhs:<{ succ t₁ }> ⟶ t'hΓ:∅ = Γ⊢ <{ ~(Γ) ⊢ ~(t') ⦂ Nat }> t:Tmτ:TyΓ:Contextt₁:Tmt':Tmhs:<{ succ t₁ }> ⟶ t'h:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>⊢ <{ ∅ ⊢ ~(t') ⦂ Nat }> cases hs with t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ succ t₁' ⦂ Nat }> t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₁') ⦂ Nat }> t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ ∅ = ∅ t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁' All goals completed! 🐙 t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ ∅ = ∅ All goals completed! 🐙 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 }> All goals completed! 🐙 t:Tmτ:TyΓ✝:ContextΓ:Contextt₁:Tmh:<{ ~(Γ) ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = Γ → <{ ~(Γ) ⊢ ~(t') ⦂ Nat }>t':Tmhs:<{ pred t₁ }> ⟶ t'hΓ:∅ = Γ⊢ <{ ~(Γ) ⊢ ~(t') ⦂ Nat }> t:Tmτ:TyΓ:Contextt₁:Tmt':Tmhs:<{ pred t₁ }> ⟶ t'h:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>⊢ <{ ∅ ⊢ ~(t') ⦂ Nat }> cases hs with t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ pred t₁' ⦂ Nat }> t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ <{ ∅ ⊢ ~(t₁') ⦂ Nat }> t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁'t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ ∅ = ∅ t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁' All goals completed! 🐙 t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∀ (t' : Tm), t₁ ⟶ t' → ∅ = ∅ → <{ ∅ ⊢ ~(t') ⦂ Nat }>t₁':Tmhst:t₁ ⟶ t₁'⊢ ∅ = ∅ All goals completed! 🐙 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 }> All goals completed! 🐙 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 }> 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 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 }> All goals completed! 🐙 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 }> 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 }>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 }> 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 }> 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₁'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: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₁' All goals completed! 🐙 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₁'⊢ ∅ = ∅ All goals completed! 🐙 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 }> All goals completed! 🐙 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 }> 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 }>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 }> 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 }> All goals completed! 🐙 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 }> 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₂'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: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₂' All goals completed! 🐙 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₂'⊢ ∅ = ∅ All goals completed! 🐙 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') ⦂ ~(τ₀) }> 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 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₃ ⦂ ~(τ₀) }> 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 }>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: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: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 }> 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₁'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: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₁' All goals completed! 🐙 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₁'⊢ ∅ = ∅ All goals completed! 🐙 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₂) ⦂ ~(τ₀) }> All goals completed! 🐙 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₃) ⦂ ~(τ₀) }> All goals completed! 🐙 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₂) ⦂ ~(τ₀) }> All goals completed! 🐙 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₃) ⦂ ~(τ₀) }> All goals completed! 🐙

6.7.1.3. Progress🔗

Exercise★★★★(StlcArith.progress)
theorem progress (t : Tm) (τ : Ty) (hτ : <{ ∅ ⊢ ~t ⦂ ~τ }>) : t.IsValue ∨ ∃ t', t ⟶ t' := t:Tmτ:Tyhτ:<{ ∅ ⊢ ~(t) ⦂ ~(τ) }>⊢ t.IsValue ∨ ∃ t', t ⟶ t' solution! t:Tmτ:TyΓ:ContexthΓ:∅ = Γhτ:<{ ~(Γ) ⊢ ~(t) ⦂ ~(τ) }>⊢ t.IsValue ∨ ∃ t', t ⟶ t' induction hτ with t:Tmτ:TyΓ✝:ContextΓ:Contextx:Stringτ₁:Tyh:Γ[x] = some τ₁hΓ:∅ = Γ⊢ (StlcArith.Tm.var x).IsValue ∨ ∃ t', StlcArith.Tm.var x ⟶ t' 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. t:Tmτ:TyΓ:Contextx:Stringτ₁:Tyh:none = some τ₁⊢ (StlcArith.Tm.var x).IsValue ∨ ∃ t', StlcArith.Tm.var x ⟶ t' All goals completed! 🐙 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' t:Tmτ:TyΓ:ContextΓ✝:Contextx✝:Stringτ₁✝:Tyτ₂✝:Tyt₁✝:Tmh✝:<{ ~(x✝ →ₚ τ₂✝ ; Γ✝) ⊢ ~(t₁✝) ⦂ ~(τ₁✝) }>h_ih✝:∅ = x✝ →ₚ τ₂✝ ; Γ✝ → t₁✝.IsValue ∨ ∃ t', t₁✝ ⟶ t'hΓ:∅ = Γ✝⊢ <{ λ ~x✝ : τ₂✝ . t₁✝ }>.IsValue All goals completed! 🐙 t:Tmτ:TyΓ:ContextΓ✝:Contextn:NathΓ:∅ = Γ✝⊢ (StlcArith.Tm.const n).IsValue ∨ ∃ t', StlcArith.Tm.const n ⟶ t' t:Tmτ:TyΓ:ContextΓ✝:Contextn:NathΓ:∅ = Γ✝⊢ (StlcArith.Tm.const n).IsValue All goals completed! 🐙 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: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' 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 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 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 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' 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 }> 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 All goals completed! 🐙 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' All goals completed! 🐙 t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuehs₂:∃ t', t₂ ⟶ t'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t' t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t' t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ <{ t₁ t₂ }> ⟶ <{ t₁ t₂' }> t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hv₁:t₁.IsValuet₂':Tmh:t₂ ⟶ t₂'⊢ t₁.IsValuet: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: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₁.IsValuet: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₂' All goals completed! 🐙 t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t'hs₁:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t' t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ ∃ t', <{ t₁ t₂ }> ⟶ t' t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ <{ t₁ t₂ }> ⟶ <{ t₁' t₂ }> t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{ ∅ ⊢ ~(t₁) ⦂ τ₂ → τ₁ }>h₂:<{ ∅ ⊢ ~(t₂) ⦂ ~(τ₂) }>ih₁:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'ih₂:∅ = ∅ → t₂.IsValue ∨ ∃ t', t₂ ⟶ t't₁':Tmh:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁' All goals completed! 🐙 t:Tmτ:TyΓ✝:ContextΓ:Contextt₁:Tmh:<{ ~(Γ) ⊢ ~(t₁) ⦂ Nat }>ih:∅ = Γ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'hΓ:∅ = Γ⊢ <{ succ t₁ }>.IsValue ∨ ∃ t', <{ succ t₁ }> ⟶ t' t:Tmτ:TyΓ✝:ContextΓ:Contextt₁:Tmh:<{ ~(Γ) ⊢ ~(t₁) ⦂ Nat }>ih:∅ = Γ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'hΓ:∅ = Γ⊢ ∃ t', <{ succ t₁ }> ⟶ t' t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'⊢ ∃ t', <{ succ t₁ }> ⟶ t' cases ih rfl with t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'hv:t₁.IsValue⊢ ∃ t', <{ succ t₁ }> ⟶ t' cases hv with t:Tmτ:TyΓ:Contextx✝:Stringτ₂✝:Tyt₁✝:Tmh:<{ ∅ ⊢ λ ~x✝ : τ₂✝ . t₁✝ ⦂ Nat }>ih:∅ = ∅ → <{ λ ~x✝ : τ₂✝ . t₁✝ }>.IsValue ∨ ∃ t', <{ λ ~x✝ : τ₂✝ . t₁✝ }> ⟶ t'⊢ ∃ t', <{ succ (λ ~x✝ : τ₂✝ . t₁✝) }> ⟶ t' All goals completed! 🐙 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' 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) All goals completed! 🐙 t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'hs:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ succ t₁ }> ⟶ t' t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmhst:t₁ ⟶ t₁'⊢ ∃ t', <{ succ t₁ }> ⟶ t' t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmhst:t₁ ⟶ t₁'⊢ <{ succ t₁ }> ⟶ <{ succ t₁' }> t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁' All goals completed! 🐙 t:Tmτ:TyΓ✝:ContextΓ:Contextt₁:Tmh:<{ ~(Γ) ⊢ ~(t₁) ⦂ Nat }>ih:∅ = Γ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'hΓ:∅ = Γ⊢ <{ pred t₁ }>.IsValue ∨ ∃ t', <{ pred t₁ }> ⟶ t' t:Tmτ:TyΓ✝:ContextΓ:Contextt₁:Tmh:<{ ~(Γ) ⊢ ~(t₁) ⦂ Nat }>ih:∅ = Γ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'hΓ:∅ = Γ⊢ ∃ t', <{ pred t₁ }> ⟶ t' t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'⊢ ∃ t', <{ pred t₁ }> ⟶ t' cases ih rfl with t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'hv:t₁.IsValue⊢ ∃ t', <{ pred t₁ }> ⟶ t' cases hv with t:Tmτ:TyΓ:Contextx✝:Stringτ₂✝:Tyt₁✝:Tmh:<{ ∅ ⊢ λ ~x✝ : τ₂✝ . t₁✝ ⦂ Nat }>ih:∅ = ∅ → <{ λ ~x✝ : τ₂✝ . t₁✝ }>.IsValue ∨ ∃ t', <{ λ ~x✝ : τ₂✝ . t₁✝ }> ⟶ t'⊢ ∃ t', <{ pred (λ ~x✝ : τ₂✝ . t₁✝) }> ⟶ t' All goals completed! 🐙 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' 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) All goals completed! 🐙 t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t'hs:∃ t', t₁ ⟶ t'⊢ ∃ t', <{ pred t₁ }> ⟶ t' t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmhst:t₁ ⟶ t₁'⊢ ∃ t', <{ pred t₁ }> ⟶ t' t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmhst:t₁ ⟶ t₁'⊢ <{ pred t₁ }> ⟶ <{ pred t₁' }> t:Tmτ:TyΓ:Contextt₁:Tmh:<{ ∅ ⊢ ~(t₁) ⦂ Nat }>ih:∅ = ∅ → t₁.IsValue ∨ ∃ t', t₁ ⟶ t't₁':Tmhst:t₁ ⟶ t₁'⊢ t₁ ⟶ t₁' All goals completed! 🐙 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' 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' 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 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 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 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' All goals completed! 🐙 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 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' All goals completed! 🐙 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' 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₂) All goals completed! 🐙 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' 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' 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₂' }> 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₁.IsValuet: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: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₁.IsValuet: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₂' All goals completed! 🐙 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' 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' 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₂ }> 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₁' All goals completed! 🐙 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' 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' 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 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 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' All goals completed! 🐙 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 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' 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₂ All goals completed! 🐙 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' 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₃ All goals completed! 🐙 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' 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' 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₃ }> 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₁' All goals completed! 🐙
end StlcArith
Source revision: 9e5dba0, committed 2026-09-25 03:12 UTC