To start off, we impose two "structural rules" that are
independent of any particular type constructor: a rule of
transitivity, which says intuitively that, if σ is
better (richer, safer) than υ and υ is better than τ,
then σ is better than τ...
σ <: υ υ <: τ
---------------- (trans)
σ <: τ
... and a rule of reflexivity, since certainly any type τ is
as good as itself:
Now we consider the individual type constructors, one by one,
beginning with product types. We consider one pair to be a subtype
of another if each of its components is.
The basic intuition is that it is always safe to use a "bigger"
record in place of a "smaller" one. That is, given a record type,
adding extra fields will always result in a subtype. If some code
is expecting a record with fields x and y, it is perfectly safe
for it to receive a record with fields x, y, and z; the z
field will simply be ignored. For example,
We can also create a subtype of a record type by replacing the type
of one of its fields with a subtype. If some code is expecting a
record with a field x of type τ, it will be happy with a record
having a field x of type σ as long as σ is a subtype of
τ. For example,
{x:Student} <: {x:Person}
This is known as "depth subtyping".
Finally, although the fields of a record type are written in a
particular order, the order does not really matter. For example,
{name:String,age:Nat} <: {age:Nat,name:String}
This is known as "permutation subtyping".
We could formalize these requirements in a single subtyping rule
for records as follows:
∀ jk in j₁..jn,
∃ ip in i₁..im, such that
jk=ip and σp <: τk
---------------------------------- (rcd)
{i₁:σ₁...im:σm} <: {j₁:τ₁...jn:τn}
That is, the record on the left should have all the field labels of
the one on the right (and possibly more), while the types of the
common fields should be in the subtype relation.
However, this rule is rather heavy and hard to read, so it is often
decomposed into three simpler rules, which can be combined using
trans to achieve all the same effects.
First, adding fields to the end of a record type gives a subtype:
n > m
--------------------------------- (rcdWidth)
{i₁:τ₁...in:τn} <: {i₁:τ₁...im:τm}
We can use rcdWidth to drop later fields of a multi-field
record while keeping earlier fields, showing for example that
{age:Nat,name:String} <: {age:Nat}.
Second, subtyping can be applied inside the components of a compound
record type:
For example, we can use rcdDepth and rcdWidth together to
show that {y:Student, x:Nat} <: {y:Person}.
Third, subtyping can reorder fields. For example, we
want {name:String, gpa:Nat, age:Nat} <: Person, but we
haven't quite achieved this yet: using just rcdDepth and
rcdWidth we can only drop fields from the end of a record
type. So we add:
{i₁:σ₁...in:σn} is a permutation of {j₁:τ₁...jn:τn}
--------------------------------------------------- (rcdPerm)
{i₁:σ₁...in:σn} <: {j₁:τ₁...jn:τn}
It is worth noting that full-blown language designs may choose not
to adopt all of these subtyping rules. For example, in Java:
Each class member (field or method) can be assigned a single
index, adding new indices "on the right" as more members are
added in subclasses (i.e., no permutation for classes).
A class may implement multiple interfaces -- so-called "multiple
inheritance" of interfaces (i.e., permutation is allowed for
interfaces).
In early versions of Java, a subclass could not change the
argument or result types of a method of its superclass (i.e., no
depth subtyping or no arrow subtyping, depending how you look at
it).
Finally, it is convenient to give the subtype relation a maximum
element -- a type that lies above every other type and is
inhabited by all (well-typed) values. We do this by adding to the
language one new type constant, called ⊤ (pronounced "⊤" and written ⊤),
together with a subtyping rule that places it above every other type in the
subtype relation:
-------- (⊤)
σ <: ⊤
The ⊤ type is an analog of the Object type in Java and C#.
What is the smallest type τ that makes the following
assertion true?
a:A ⊢ (λp:(A×τ). (p.snd) (p.fst)) (a, λz:A. z) ⦂ A
(A) ⊤
(B) A
(C) ⊤→⊤
(D) ⊤→A
(E) A→A
(F) A→⊤
Quiz
What is the largest type τ that makes the following
assertion true?
a:A ⊢ (λp:(A×τ). (p.snd) (p.fst)) (a, λz:A.z) ⦂ A
(A) ⊤
(B) A
(C) ⊤→⊤
(D) ⊤→A
(E) A→A
(F) A→⊤
Quiz
"The type Bool has no proper subtypes." (I.e., the only
type smaller than Bool is Bool itself.)
(A) True
(B) False
Quiz
"Suppose σ, τ₁, and τ₂ are types with σ <: τ₁ → τ₂. Then
σ itself is an arrow type -- i.e., σ = σ₁ → σ₂ for some σ₁
and σ₂ -- with τ₁ <: σ₁ and σ₂ <: τ₂."
Most of the definitions needed to formalize what we've discussed
above -- in particular, the syntax and operational semantics of
the language -- are identical to what we saw in the last chapter.
We just need to extend the typing relation with the subsumption
rule and add a new inductive definition for the subtyping
relation. Let's first do the identical bits.
Omitting records, to avoid dealing with "..." stuff.
inductiveTy:Typewhere|top:Ty|bool:Ty|base:String→Ty|arrow:Ty→Ty→Ty|unit:Ty|prod:Ty→Ty→TyinductiveTm:Typewhere|var:String→Tm|app:Tm→Tm→Tm|abs:String→Ty→Tm→Tm|tru:Tm|fls:Tm|ite:Tm→Tm→Tm→Tm|unit:Tm|pair:Tm→Tm→Tm|fst:Tm→Tm|snd:Tm→TmNotationsyntax:50stlcTy:51" × "stlcTy:50:stlcTysyntax:50stlcTy:51" + "stlcTy:50:stlcTysyntax:max" ⊤ ":stlcTysyntax:51" [ "stlcTy:50" ] ":stlcTyopenLeaninscopedmacro_rules(kind:=Stlc.tyBracket)|`(<{~$τ:term}>)=>pureτ|`(<{($τ:stlcTy)}>)=>`(<{$τ:stlcTy}>)|`(<{⊤}>)=>`(Ty.top)|`(<{$x:ident}>)=>matchx.getId.toStringwith|"Bool"=>`(Ty.bool)|"Unit"=>`(Ty.unit)|_=>`(Ty.base$(quotex.getId.toString))|`(<{$τ₁:stlcTy→$τ₂:stlcTy}>)=>`(Ty.arrow<{$τ₁:stlcTy}><{$τ₂:stlcTy}>)|`(<{$τ₁:stlcTy×$τ₂:stlcTy}>)=>`(Ty.prod<{$τ₁:stlcTy}><{$τ₂:stlcTy}>)|`(<{$τ₁:stlcTy->$τ₂:stlcTy}>)=>`(Ty.arrow<{$τ₁:stlcTy}><{$τ₂:stlcTy}>)Ty.top.prodTy.top : Ty#check<{⊤×⊤}>Ty.bool.arrowTy.top : Ty#check<{Bool→⊤}>(Ty.bool.prodTy.unit).arrow(Ty.base"Nat") : Ty#check<{(Bool×Unit)->Nat}>scopedsyntax:50"if "stlcTm:51" then "stlcTm:50" else "stlcTm:50:stlcTmscopedsyntax:max" ( "stlcTm:60" , "stlcTm:60" ) ":stlcTmopenLeaninscopedmacro_rules(kind:=Stlc.tmBracket)|`(<{~$e:term}>)=>puree|`(<{($t:stlcTm)}>)=>`(<{$t:stlcTm}>)|`(<{$x:ident}>)=>matchx.getId.toStringwith|"Nat"=>Macro.throwErrorAtx"`Nat` is a type, not a term"|"Unit"=>Macro.throwErrorAtx"`Unit` is a type, not a term"|"fst"=>Macro.throwErrorAtx"`fst` must be applied to an argument"|"snd"=>Macro.throwErrorAtx"`snd` must be applied to an argument"|"unit"=>`(Tm.unit)|"true"=>`(Tm.tru)|"false"=>`(Tm.fls)|_=>`(Tm.var$(quotex.getId.toString))|`(<{λ$x:$τ.$t}>)=>do`(Tm.abs$(←Stlc.varStrx)<{$τ:stlcTy}><{$t:stlcTm}>)|`(<{$t₁:stlcTm$t₂:stlcTm}>)=>matcht₁with|`(stlcTm|$f:ident)=>matchf.getId.toStringwith|"fst"=>`(Tm.fst<{$t₂:stlcTm}>)|"snd"=>`(Tm.snd<{$t₂:stlcTm}>)|_=>`(Tm.app<{$t₁:stlcTm}><{$t₂:stlcTm}>)|_=>`(Tm.app<{$t₁:stlcTm}><{$t₂:stlcTm}>)|`(<{if$cthen$telse$e}>)=>`(Tm.ite<{$c:stlcTm}><{$t:stlcTm}><{$e:stlcTm}>)|`(<{($t₁:stlcTm,$t₂:stlcTm)}>)=>`(Tm.pair<{$t₁:stlcTm}><{$t₂:stlcTm}>)openLeanin/-- Is `s` usable as a bare variable in `stlcTm` rather than as reserved syntax? -/defisPlainTmVarName(s:String):Bool:=Stlc.isPlainNames&&s!="Bool"&&s!="unit"&&s!="Unit"&&s!="if"openLeanPrettyPrinterDelaboratorSubExprin/-- Rebuild `stlcTy` concrete syntax from a `Ty` value. -/partialdefdelabTyInner:DelabM(TSyntax`stlcTy):=doletstx←match_expr←getExprwith|Ty.bool=>`(stlcTy|$(mkIdent`Bool):ident)|Ty.unit=>`(stlcTy|$(mkIdent`Unit):ident)|Ty.top=>`(stlcTy|⊤)|Ty.arrow__=>doleta←withAppFn<|withAppArgdelabTyInnerletb←withAppArgdelabTyInner`(stlcTy|$a→$b)|Ty.prod__=>doleta←withAppFn<|withAppArgdelabTyInnerletb←withAppArgdelabTyInner`(stlcTy|$a×$b)|Ty.base_=>doletb←withAppArgdelab`(stlcTy|~($b))|_=>domatch←delabwith|`($i:ident)=>`(stlcTy|$i:ident)|e=>`(stlcTy|~$e)(⟨·⟩)<$>annotateTermInfo⟨stx.raw⟩openLeanPrettyPrinterDelaboratorSubExprin/-- Rebuild `stlcTm` concrete syntax from a `Tm` value. -/partialdefdelabTmInner:DelabM(TSyntax`stlcTm):=doletstx←match_expr←getExprwith|Tm.var_=>doletx←withAppArgdelabmatchxwith|`($s:str)=>ifisPlainTmVarNames.getStringthen`(stlcTm|$(mkIdent(Name.mkSimples.getString)):ident)elseletvar:Term:=mkIdent``Tm.var`(stlcTm|~($var$x))|_=>letvar:Term:=mkIdent``Tm.var`(stlcTm|~($var$x))|Tm.app__=>doletf←withAppFn<|withAppArgdelabTmInnerleta←withAppArgdelabTmInner`(stlcTm|$f$a)|Tm.abs___=>doletx←withAppFn<|withAppFn<|withAppArgStlc.delabVarInnerletτ←withAppFn<|withAppArgdelabTyInnerlett←withAppArgdelabTmInner`(stlcTm|λ$x:$τ.$t)|Tm.ite___=>doletc←withAppFn<|withAppFn<|withAppArgdelabTmInnerlett←withAppFn<|withAppArgdelabTmInnerlete←withAppArgdelabTmInner`(stlcTm|if$cthen$telse$e)|Tm.pair__=>doleta←withAppFn<|withAppArgdelabTmInnerletb←withAppArgdelabTmInner`(stlcTm|($a,$b))|Tm.fst_=>doletb←withAppArgdelabTmInner`(stlcTm|$(mkIdent`fst):ident$b)|Tm.snd_=>doletb←withAppArgdelabTmInner`(stlcTm|$(mkIdent`snd):ident$b)|Tm.unit=>do`(stlcTm|$(mkIdent`unit):ident)|Tm.tru=>do`(stlcTm|$(mkIdent`true):ident)|Tm.fls=>do`(stlcTm|$(mkIdent`false):ident)|_=>do-- `subst` is defined below, so it is matched by name rather than with-- `match_expr`; a substitution prints in its own bracket notation.lete←getExprife.getAppFn.constName?==some`SltcExtended.subst&&e.getAppNumArgs==3thenletx←withAppFn<|withAppFn<|withAppArgStlc.delabVarInnerlets←withAppFn<|withAppArgdelabTmInnerlett←withAppArgdelabTmInner`(stlcTm|[$x:=$s]$t)elsematch←delabwith|`($i:ident)=>`(stlcTm|$i:ident)|e=>`(stlcTm|~$e)(⟨·⟩)<$>annotateTermInfo⟨stx.raw⟩openLeanPrettyPrinterDelaboratorSubExprin@[delabapp.StlcSub.Ty.bool,delabapp.StlcSub.Ty.arrow,delabapp.StlcSub.Ty.unit,delabapp.StlcSub.Ty.prod,delabapp.StlcSub.Ty.base,delabapp.StlcSub.Ty.top]defdelabTy:Delab:=whenPPOptiongetPPNotationdoguard<|match_expr←getExprwith|Ty.bool=>true|Ty.arrow__=>true|Ty.prod__=>true|Ty.base_=>true|Ty.top=>true|Ty.unit=>true|_=>falsematch←delabTyInnerwith|`(stlcTy|~$e)=>puree|e=>`(<{$e:stlcTy}>)openLeanPrettyPrinterDelaboratorSubExprin@[delabapp.StlcSub.Tm.var,delabapp.StlcSub.Tm.app,delabapp.StlcSub.Tm.abs,delabapp.StlcSub.Tm.ite,delabapp.StlcSub.Tm.pair,delabapp.StlcSub.Tm.fst,delabapp.StlcSub.Tm.snd,delabapp.StlcSub.Tm.unit,delabapp.StlcSub.Tm.tru,delabapp.StlcSub.Tm.fls]defdelabTm:Delab:=whenPPOptiongetPPNotationdoguard<|match_expr←getExprwith|Tm.var_=>true|Tm.app__=>true|Tm.abs___=>true|Tm.ite___=>true|Tm.unit=>true|Tm.tru=>true|Tm.fls=>true|Tm.pair__=>true|Tm.fst_=>true|Tm.snd_=>true|_=>falsematch←delabTmInnerwith|`(stlcTm|~($e))=>puree|`(stlcTm|~$e)=>puree|e=>`(<{$e:stlcTm}>)
Checks that the extended grammar parses the way it should.
The definition of substitution remains exactly the same as for the
pure STLC.
sectionset_optionhygienefalseinlocalmacro_rules(kind:=Stlc.tmBracket)|`(<{[$x:=$s]$t}>)=>do`(subst$(←Stlc.varStrx)<{$s:stlcTm}><{$t:stlcTm}>)defdeclaration uses `sorry`declaration uses `sorry`declaration uses `sorry`subst(x:String)(s:Tm)(t:Tm):Tm:=matchtwith-- pure STLC|.vary=>ifx=ythenselset|<{λ~y:~τ.~t₁}>=>ifx=ythentelse<{λ~y:~τ.[~x:=~s]~t₁}>|<{~t₁~t₂}>=><{([~x:=~s]~t₁)([~x:=~s]~t₂)}>-- unit|.unit=><{unit}>-- bools|<{true}>=><{true}>|<{false}>=><{false}>|<{if~t₁then~t₂else~t₃}>=><{if[~x:=~s]~t₁then[~x:=~s]~t₂else[~x:=~s]~t₃}>-- Complete the following cases when you do the `products` exercise later|<{(~t₁,~t₂)}>=>sorry|Tm.fstt=>sorry|Tm.sndt=>sorryendmacro_rules(kind:=Stlc.tmBracket)|`(<{[$x:=$s]$t}>)=>do`(subst$(←Stlc.varStrx)<{$s:stlcTm}><{$t:stlcTm}>)
inductiveTm.IsValue:Tm→Propwhere|abs:∀xτ₂t₁,IsValue<{λ~x:~τ₂.~t₁}>|tru:IsValue<{true}>|fls:IsValue<{false}>|unit:IsValue.unit-- Fill in more rules when you do the `products` exercise later-- FILL IN HEREattribute[StlcSubEval]Tm.IsValue.absTm.IsValue.truTm.IsValue.flsTm.IsValue.unitsectionset_optionhygienefalseinlocalnotation:40t:41" ⟶ "t':41=>Steptt'inductiveStep:Tm→Tm→Propwhere-- pure STLC|appAbs(x:String)(τ₂:Ty)(t₁v₂:Tm):v₂.IsValue→<{(λ~x:~τ₂.~t₁)~v₂}>⟶<{[~x:=~v₂]~t₁}>|app₁(t₁t₁'t₂:Tm):t₁⟶t₁'→<{~t₁~t₂}>⟶<{~t₁'~t₂}>|app₂(v₁t₂t₂':Tm):v₁.IsValue→t₂⟶t₂'→<{~v₁~t₂}>⟶<{~v₁~t₂'}>-- booleans|ifStep(t₁t₁'t₂t₃:Tm)(h:t₁⟶t₁'):<{if~t₁then~t₂else~t₃}>⟶<{if~t₁'then~t₂else~t₃}>|ifTrue(t₂t₃:Tm):<{iftruethen~t₂else~t₃}>⟶t₂|ifFalse(t₂t₃:Tm):<{iffalsethen~t₂else~t₃}>⟶t₃-- Fill in more rules when you do the `products` exercise later-- FILL IN HEREendscopednotation:40t:41" ⟶ "t':41=>Steptt'scopednotation:40t:41" ⟶* "t':41=>MultiSteptt'-- Be sure to add your constructors for pairs to this list laterattribute[StlcSubEval]Step.appAbsStep.app₁Step.app₂Step.ifStepStep.ifTrueStep.ifFalse-- FILL IN HERE
sectionset_optionhygienefalseinlocalnotation:40τ:41" <: "τ':41=>Subtypeττ'inductiveSubtype:Ty→Ty→Propwhere|refl{τ:Ty}:τ<:τ|trans{συτ:Ty}(h₁:σ<:υ)(h₂:υ<:τ):σ<:τ|top{σ:Ty}:σ<:<{⊤}>|arrow{σ₁σ₂τ₁τ₂:Ty}(h₁:τ₁<:σ₁)(h₂:σ₂<:τ₂):<{~σ₁→~σ₂}><:<{~τ₁→~τ₂}>-- Fill in more rules when you do the `products` exercise later-- FILL IN HEREendscopednotation:40τ:41" <: "τ':41=>Subtypeττ'attribute[StlcSubTyping]Subtype.reflSubtype.transSubtype.topSubtype.arrow-- FILL IN HERE
Note that we don't need any special rules for base types (Bool
and Base): they are automatically subtypes of themselves (by
refl) and ⊤ (by top), and that's all we want.
The only change to the typing relation is the addition of the rule
of subsumption, sub.
abbrevContext:=PartialMapStringTyNotation encoding: contexts and judgments
The context grammar stlcCtx is reused as well; only the map it denotes is new,
since the types it stores are this language's. As with subst, the judgment
rule is introduced twice: local and hygiene-free while the relation is being
declared, then again for real.
openLeanin/-- The `Context` denoted by a context expression. -/partialdefctxTerm(G:TSyntax`stlcCtx):MacroMTerm:=matchGwith|`(stlcCtx|∅)=>`((∅:Context))|`(stlcCtx|~$e)=>puree|`(stlcCtx|$x:stlcVar↦$τ:stlcTy;$G:stlcCtx)=>do`(PartialMap.update$(←ctxTermG)$(←Stlc.varStrx)<{$τ:stlcTy}>)|_=>Macro.throwUnsupportedsectionStlcExtendedset_optionhygienefalseinlocalmacro_rules(kind:=Stlc.judgeBracket)|`(<{$G:stlcCtx⊢$t:stlcTm⦂$τ:stlcTy}>)=>do`(HasType$(←ctxTermG)<{$t:stlcTm}><{$τ:stlcTy}>)inductiveHasType:Context→Tm→Ty→Propwhere-- pure STLC|var(Γ:Context)(x:String)(τ₁:Ty)(h:Γ[x]=someτ₁):<{~Γ⊢~(Tm.varx)⦂~τ₁}>|abs(Γ:Context)(x:String)(τ₁τ₂:Ty)(t₁:Tm)(h:<{~x↦~τ₂;~Γ⊢~t₁⦂~τ₁}>):<{~Γ⊢λ~x:~τ₂.~t₁⦂~τ₂→~τ₁}>|app(Γ:Context)(τ₁τ₂:Ty)(t₁t₂:Tm)(h₁:<{~Γ⊢~t₁⦂~τ₂→~τ₁}>)(h₂:<{~Γ⊢~t₂⦂~τ₂}>):<{~Γ⊢~t₁~t₂⦂~τ₁}>-- booleans|tru(Γ:Context):<{~Γ⊢true⦂Bool}>|fls(Γ:Context):<{~Γ⊢false⦂Bool}>|ite(Γ:Context)(t₁t₂t₃:Tm)(τ:Ty)(h₁:<{~Γ⊢~t₁⦂Bool}>)(h₂:<{~Γ⊢~t₂⦂~τ}>)(h₃:<{~Γ⊢~t₃⦂~τ}>):<{~Γ⊢if~t₁then~t₂else~t₃⦂~τ}>-- unit|unit(Γ:Context):<{~Γ⊢unit⦂Unit}>-- subsumption|sub(Γ:Context)(t₁:Tm)(τ₁τ₂:Ty)(ht:<{~Γ⊢~t₁⦂~τ₁}>)(hs:τ₁<:τ₂):<{~Γ⊢~t₁⦂~τ₂}>-- Fill in more rules when you do the `products` exercise later-- FILL IN HERE-- Make sure to add your constructors hereattribute[StlcSubTyping]HasType.varHasType.absHasType.appHasType.iteHasType.truHasType.flsHasType.unit-- FILL IN HERE
We deliberately exclude HasType.sub from the list of constructors with the
StlcSubTyping. apply_rules using StlcSubTyping will search for derivations
without using the subtyping rule; if you want to make use of it in a derivation you will
need to do so yourself.
Notation encoding: the judgment, for real
Closing the section retires the hygiene-free rule; the same rule is then
declared again, hygienically, for every later use, and a pair of unexpanders
prints judgments back in their own notation.
endStlcExtendedscopedmacro_rules(kind:=Stlc.judgeBracket)|`(<{$G:stlcCtx⊢$t:stlcTm⦂$τ:stlcTy}>)=>do`(HasType$(←ctxTermG)<{$t:stlcTm}><{$τ:stlcTy}>)openLeanPrettyPrinterin/-- Rebuild `stlcCtx` syntax from the term syntax of a `Context`, so that a
context prints as `x ↦ Nat ; Γ` rather than as a chain of map updates. -/partialdefunexpandCtx:Term→UnexpandM(TSyntax`stlcCtx)|`(∅)=>`(stlcCtx|∅)|`($x:str→ₚ$τ)=>dounexpandCtx(←`($x→ₚ$τ;∅))|`($x:str→ₚ$τ;$G)=>doletG'←unexpandCtxGletx':TSyntax`stlcVar←ifStlc.isPlainNamex.getStringthen`(stlcVar|$(mkIdent(Name.mkSimplex.getString)):ident)else`(stlcVar|~$x)matchτwith|`(<{$T':stlcTy}>)=>`(stlcCtx|$x':stlcVar↦$T';$G')|_=>`(stlcCtx|$x':stlcVar↦~($τ);$G')|G=>`(stlcCtx|~($G))openLeanPrettyPrinterin@[app_unexpanderHasType]defHasType.unexpand:Unexpander|`($_$G<{$t:stlcTm}><{$τ:stlcTy}>)=>do`(<{$(←unexpandCtxG)⊢$t⦂$τ}>)|`($_$G<{$t:stlcTm}>$τ)=>do`(<{$(←unexpandCtxG)⊢$t⦂~($τ)}>)|`($_$G$t<{$τ:stlcTy}>)=>do`(<{$(←unexpandCtxG)⊢~($t)⦂$τ}>)|`($_$G$t$τ)=>do`(<{$(←unexpandCtxG)⊢~($t)⦂~($τ)}>)|_=>throw()
theoremprogress(t:Tm)(τ:Ty)(h:<{∅⊢~t⦂~τ}>):t.IsValue∨∃t',t⟶t':=t:Tmτ:Tyh:<{∅⊢~(t)⦂~(τ)}>⊢ t.IsValue∨∃t',t⟶t't:Tmτ:TyΓ:Contextheq:∅=Γh:<{~(Γ)⊢~(t)⦂~(τ)}>⊢ t.IsValue∨∃t',t⟶t'Alternative `snd` has not been providedAlternative `pair` has not been providedAlternative `fst` has not been providedinductionhwith(t:Tmτ:TyΓ:Contextt✝:Tmτ₁✝:Tyτ₂✝:Tyh✝:<{∅⊢~(t✝)⦂τ₁✝×τ₂✝}>h_ih✝:∅=∅→t✝.IsValue∨∃t',t✝⟶t'⊢ <{sndt✝}>.IsValue∨∃t',<{sndt✝}>⟶t';first|t:Tmτ:TyΓ:Contextt✝:Tmτ₁✝:Tyτ₂✝:Tyh✝:<{∅⊢~(t✝)⦂τ₁✝×τ₂✝}>h_ih✝:∅=∅→t✝.IsValue∨∃t',t✝⟶t'⊢ <{sndt✝}>.IsValue∨∃t',<{sndt✝}>⟶t'-- discharge cases where `t` is obviously a value|try(t:Tmτ:TyΓ:Contextt✝:Tmτ₁✝:Tyτ₂✝:Tyh✝:<{∅⊢~(t✝)⦂τ₁✝×τ₂✝}>h_ih✝:∅=∅→t✝.IsValue∨∃t',t✝⟶t'⊢ <{sndt✝}>.IsValue;t:Tmτ:TyΓ:Contextt✝:Tmτ₁✝:Tyτ₂✝:Tyh✝:<{∅⊢~(t✝)⦂τ₁✝×τ₂✝}>h_ih✝:∅=∅→t✝.IsValue∨∃t',t✝⟶t'⊢ <{sndt✝}>.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'⊢ <{t₁t₂}>.IsValue∨∃t',<{t₁t₂}>⟶t't:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{∅⊢~(t₁)⦂τ₂→τ₁}>h₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'⊢ ∃t',<{t₁t₂}>⟶t';t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{∅⊢~(t₁)⦂τ₂→τ₁}>h₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'h✝:t₁.IsValue⊢ ∃t',<{t₁t₂}>⟶t't:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{∅⊢~(t₁)⦂τ₂→τ₁}>h₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'h✝:∃t',t₁⟶t'⊢ ∃t',<{t₁t₂}>⟶t'-- t₁ is a valuecase_ht₁t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{∅⊢~(t₁)⦂τ₂→τ₁}>h₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ht₁:t₁.IsValue⊢ ∃t',<{t₁t₂}>⟶t't:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{∅⊢~(t₁)⦂τ₂→τ₁}>h₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ht₁:t₁.IsValueh✝:t₂.IsValue⊢ ∃t',<{t₁t₂}>⟶t't:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{∅⊢~(t₁)⦂τ₂→τ₁}>h₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ht₁:t₁.IsValueh✝:∃t',t₂⟶t'⊢ ∃t',<{t₁t₂}>⟶t'-- t₂ is a valuecase_ht₂t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{∅⊢~(t₁)⦂τ₂→τ₁}>h₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ht₁:t₁.IsValueht₂:t₂.IsValue⊢ ∃t',<{t₁t₂}>⟶t't:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ht₁:t₁.IsValueht₂:t₂.IsValueh₁:t₁.IsValue→∃xσ₁t₂,t₁=<{λ~x:σ₁.t₂}>⊢ ∃t',<{t₁t₂}>⟶t't:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ht₁:t₁.IsValueht₂:t₂.IsValueh₁:t₁.IsValue→∃xσ₁t₂,t₁=<{λ~x:σ₁.t₂}>x:Stringσ:Tyv:Tmhv:t₁=<{λ~x:σ.v}>⊢ ∃t',<{t₁t₂}>⟶t't:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ht₁:t₁.IsValueht₂:t₂.IsValueh₁:t₁.IsValue→∃xσ₁t₂,t₁=<{λ~x:σ₁.t₂}>x:Stringσ:Tyv:Tmhv:t₁=<{λ~x:σ.v}>⊢ <{t₁t₂}>⟶substxt₂v;t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ht₁:t₁.IsValueht₂:t₂.IsValueh₁:t₁.IsValue→∃xσ₁t₂,t₁=<{λ~x:σ₁.t₂}>x:Stringσ:Tyv:Tmhv:t₁=<{λ~x:σ.v}>⊢ <{(λ~x:σ.v)t₂}>⟶substxt₂vAll goals completed! 🐙-- t₂ is not a valuecase_ht₂t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{∅⊢~(t₁)⦂τ₂→τ₁}>h₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ht₁:t₁.IsValueht₂:∃t',t₂⟶t'⊢ ∃t',<{t₁t₂}>⟶t't:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{∅⊢~(t₁)⦂τ₂→τ₁}>h₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ht₁:t₁.IsValuet₂':Tmht₂:t₂⟶t₂'⊢ ∃t',<{t₁t₂}>⟶t't:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{∅⊢~(t₁)⦂τ₂→τ₁}>h₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ht₁:t₁.IsValuet₂':Tmht₂:t₂⟶t₂'⊢ <{t₁t₂}>⟶<{t₁t₂'}>;All goals completed! 🐙-- t₁ is not a valuecase_ht₁t:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{∅⊢~(t₁)⦂τ₂→τ₁}>h₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ht₁:∃t',t₁⟶t'⊢ ∃t',<{t₁t₂}>⟶t't:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{∅⊢~(t₁)⦂τ₂→τ₁}>h₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t't₁':Tmht₁:t₁⟶t₁'⊢ ∃t',<{t₁t₂}>⟶t't:Tmτ:TyΓ:Contextτ₁:Tyτ₂:Tyt₁:Tmt₂:Tmh₁:<{∅⊢~(t₁)⦂τ₂→τ₁}>h₂:<{∅⊢~(t₂)⦂~(τ₂)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t't₁':Tmht₁:t₁⟶t₁'⊢ <{t₁t₂}>⟶<{t₁'t₂}>;All goals completed! 🐙t:Tmτ✝:TyΓ:Contextt₁: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'⊢ <{ift₁thent₂elset₃}>.IsValue∨∃t',<{ift₁thent₂elset₃}>⟶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',<{ift₁thent₂elset₃}>⟶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'h✝:t₁.IsValue⊢ ∃t',<{ift₁thent₂elset₃}>⟶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'h✝:∃t',t₁⟶t'⊢ ∃t',<{ift₁thent₂elset₃}>⟶t'-- t₁ is a valuecase_ht₁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'ht₁:t₁.IsValue⊢ ∃t',<{ift₁thent₂elset₃}>⟶t't:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₂:<{∅⊢~(t₂)⦂~(τ)}>h₃:<{∅⊢~(t₃)⦂~(τ)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ih₃:∅=∅→t₃.IsValue∨∃t',t₃⟶t'ht₁:t₁.IsValueh₁:t₁.IsValue→t₁=<{true}>∨t₁=<{false}>⊢ ∃t',<{ift₁thent₂elset₃}>⟶t't:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₂:<{∅⊢~(t₂)⦂~(τ)}>h₃:<{∅⊢~(t₃)⦂~(τ)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ih₃:∅=∅→t₃.IsValue∨∃t',t₃⟶t'ht₁:t₁.IsValueh₁✝:t₁.IsValue→t₁=<{true}>∨t₁=<{false}>h₁:t₁=<{true}>⊢ ∃t',<{ift₁thent₂elset₃}>⟶t't:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₂:<{∅⊢~(t₂)⦂~(τ)}>h₃:<{∅⊢~(t₃)⦂~(τ)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ih₃:∅=∅→t₃.IsValue∨∃t',t₃⟶t'ht₁:t₁.IsValueh₁✝:t₁.IsValue→t₁=<{true}>∨t₁=<{false}>h₁:t₁=<{false}>⊢ ∃t',<{ift₁thent₂elset₃}>⟶t't:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₂:<{∅⊢~(t₂)⦂~(τ)}>h₃:<{∅⊢~(t₃)⦂~(τ)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ih₃:∅=∅→t₃.IsValue∨∃t',t₃⟶t'ht₁:t₁.IsValueh₁✝:t₁.IsValue→t₁=<{true}>∨t₁=<{false}>h₁:t₁=<{true}>⊢ ∃t',<{ift₁thent₂elset₃}>⟶t't:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyh₂:<{∅⊢~(t₂)⦂~(τ)}>h₃:<{∅⊢~(t₃)⦂~(τ)}>ih₁:∅=∅→t₁.IsValue∨∃t',t₁⟶t'ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ih₃:∅=∅→t₃.IsValue∨∃t',t₃⟶t'ht₁:t₁.IsValueh₁✝:t₁.IsValue→t₁=<{true}>∨t₁=<{false}>h₁:t₁=<{false}>⊢ ∃t',<{ift₁thent₂elset₃}>⟶t't:Tmτ✝:TyΓ:Contextt₂:Tmt₃:Tmτ:Tyh₂:<{∅⊢~(t₂)⦂~(τ)}>h₃:<{∅⊢~(t₃)⦂~(τ)}>ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ih₃:∅=∅→t₃.IsValue∨∃t',t₃⟶t'ih₁:∅=∅→<{false}>.IsValue∨∃t',<{false}>⟶t'ht₁:<{false}>.IsValueh₁:<{false}>.IsValue→<{false}>=<{true}>∨<{false}>=<{false}>⊢ ∃t',<{iffalsethent₂elset₃}>⟶t't:Tmτ✝:TyΓ:Contextt₂:Tmt₃:Tmτ:Tyh₂:<{∅⊢~(t₂)⦂~(τ)}>h₃:<{∅⊢~(t₃)⦂~(τ)}>ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ih₃:∅=∅→t₃.IsValue∨∃t',t₃⟶t'ih₁:∅=∅→<{true}>.IsValue∨∃t',<{true}>⟶t'ht₁:<{true}>.IsValueh₁:<{true}>.IsValue→<{true}>=<{true}>∨<{true}>=<{false}>⊢ ∃t',<{iftruethent₂elset₃}>⟶t't:Tmτ✝:TyΓ:Contextt₂:Tmt₃:Tmτ:Tyh₂:<{∅⊢~(t₂)⦂~(τ)}>h₃:<{∅⊢~(t₃)⦂~(τ)}>ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ih₃:∅=∅→t₃.IsValue∨∃t',t₃⟶t'ih₁:∅=∅→<{true}>.IsValue∨∃t',<{true}>⟶t'ht₁:<{true}>.IsValueh₁:<{true}>.IsValue→<{true}>=<{true}>∨<{true}>=<{false}>⊢ <{iftruethent₂elset₃}>⟶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'ih₁:∅=∅→<{false}>.IsValue∨∃t',<{false}>⟶t'ht₁:<{false}>.IsValueh₁:<{false}>.IsValue→<{false}>=<{true}>∨<{false}>=<{false}>⊢ ∃t',<{iffalsethent₂elset₃}>⟶t't:Tmτ✝:TyΓ:Contextt₂:Tmt₃:Tmτ:Tyh₂:<{∅⊢~(t₂)⦂~(τ)}>h₃:<{∅⊢~(t₃)⦂~(τ)}>ih₂:∅=∅→t₂.IsValue∨∃t',t₂⟶t'ih₃:∅=∅→t₃.IsValue∨∃t',t₃⟶t'ih₁:∅=∅→<{false}>.IsValue∨∃t',<{false}>⟶t'ht₁:<{false}>.IsValueh₁:<{false}>.IsValue→<{false}>=<{true}>∨<{false}>=<{false}>⊢ <{iffalsethent₂elset₃}>⟶t₃;All goals completed! 🐙-- t₁ is not a valuecase_ht₁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'ht₁:∃t',t₁⟶t'⊢ ∃t',<{ift₁thent₂elset₃}>⟶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₁':Tmht₁:t₁⟶t₁'⊢ ∃t',<{ift₁thent₂elset₃}>⟶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₁':Tmht₁:t₁⟶t₁'⊢ <{ift₁thent₂elset₃}>⟶<{ift₁'thent₂elset₃}>;All goals completed! 🐙t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyhs:τ₁<:τ₂ht:<{∅⊢~(t₁)⦂~(τ₁)}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'⊢ t₁.IsValue∨∃t',t₁⟶t't:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyhs:τ₁<:τ₂ht:<{∅⊢~(t₁)⦂~(τ₁)}>ih:∅=∅→t₁.IsValue∨∃t',t₁⟶t'⊢ ∅=∅;All goals completed! 🐙-- Fill in products here later-- FILL IN HERE
We also need to prove an inversion lemma corresponding to a
structural fact about the typing relation that is "obvious from
the definition" in pure STLC.
Lemma: If Γ ⊢ λ x : σ₁ . t₂ ⦂ τ, then there is a type σ₂
such that x ↦ σ₁ ; Γ ⊢ t₂ ⦂ σ and σ₁ → σ₂ <: τ.
Proof: Let Γ, x, σ₁, t₂ and τ be given as
described. Proceed by induction on the derivation of Γ ⊢ λ x : σ₁ . t₂ ⦂ τ.
The cases for var and app are vacuous
as those rules cannot be used to give a type to a syntactic
abstraction.
If the last step of the derivation is a use of abs then
there is a type τ₁₂ such that τ = σ₁ → τ₁₂ and x ↦ σ₁; Γ ⊢ t₂ ⦂ τ₁₂.
Picking τ₁₂ for σ₂ gives us what we
need, since σ₁ → τ₁₂ <: σ₁ → τ₁₂ follows from rfl.
If the last step of the derivation is a use of sub then
there is a type σ such that σ <: τ and Γ ⊢ λx : σ₁, t₂ ⦂ σ.
The IH for the typing subderivation tells us that there
is some type σ₂ with σ₁ → σ₂ <: σ and x↦σ₁; Γ ⊢ t₂ ⦂ σ₂.
Picking type σ₂ gives us what we need, since σ₁ → σ₂ <: τ then follows by trans.
-- Add your lemmas for products here when you get to that exercise
-- FILL IN HERE-- FILL IN HEREunexpected end of input
The inversion lemmas for typing and for subtyping between arrow
types can be packaged up as a useful "combination lemma" telling
us exactly what we'll actually require below.
The proof of preservation now proceeds pretty much as in earlier
chapters, using the substitution lemma at the appropriate point
and the inversion lemma from above to extract structural
information from typing assumptions.
Theorem (Preservation): If t, t' are terms and τ is a type
such that ∅ ⊢ t ⦂ τ and t ⟶ t', then ∅ ⊢ t' ⦂ τ.
Proof: Let t and τ be given such that ∅ ⊢ t ⦂ τ.
We proceed by induction on the structure of this typing
derivation. The abs, unit, tru, and fls cases
are vacuous because abstractions and constants don't step. Case
var is vacuous as well, since the context is empty.
If the final step of the derivation is by app, then there
are terms t₁ and t₂ and types τ₁ and τ₂ such that t = t₁ t₂,
τ = τ₂, ∅ ⊢ t₁ ⦂ τ₁ → τ₂, and ∅ ⊢ t₂ ⦂ τ₁.
By the definition of the step relation, there are three ways
t₁ t₂ can step. Cases app₁' and app₂ follow
immediately by the induction hypotheses for the typing
subderivations and a use of app.
Suppose instead t₁ t₂ steps by appAbs. Then t₁ = λ x:σ . τ₁₂
for some type σ and term τ₁₂, and t' = [x:=t₂] τ₁₂.
By lemma abs_arrow, we have τ₁ <: σ and x:σ₁ ⊢ t₂ ⦂ τ₂. It then follows by the substitution lemma (substitution_preserves_typing) that
∅ ⊢ [x:=t₂] τ₁₂ ⦂ τ₂ as desired.
If the final step of the derivation uses rule if, then
there are terms t₁, t₂, and t₃ such that t = if t₁ then t₂ else t₃,
with ∅ ⊢ t₁ ⦂ Bool and with ∅ ⊢ t₂ ⦂ τ and ∅ ⊢ t₃ ⦂ τ. Moreover, by the induction
hypothesis, if t₁ steps to t₁' then ∅ ⊢ t₁' : Bool.
There are three cases to consider, depending on which rule was
used to show t ⟶ t'.
If t ⟶ t' by rule if, then t' = if t₁' then t₂ else t₃ with
t₁ ⟶ t₁'. By the induction hypothesis,
∅ ⊢ t₁' ⦂ Bool, and so ∅ ⊢ t' ⦂ τ by
if.
If t ⟶ t' by rule ifTrue or ifFalse, then
either t' = t₂ or t' = t₃, and ∅ ⊢ t' ⦂ τ
follows by assumption.
If the final step of the derivation is by sub, then there
is a type σ such that σ <: τ and ∅ ⊢ t ⦂ σ. The
result is immediate by the induction hypothesis for the typing
subderivation and an application of sub.
Qed.
theorempreservation{tt':Tm}{τ:Ty}(ht:<{∅⊢~t⦂~τ}>)(hs:t⟶t'):<{∅⊢~t'⦂~τ}>:=byt:Tmt':Tmτ:Tyht:<{∅⊢~(t)⦂~(τ)}>hs:t⟶t'⊢ <{∅⊢~(t')⦂~(τ)}>generalizeheq:(∅:Context)=Γathtt:Tmt':Tmτ:Tyhs:t⟶t'Γ:Contextheq:∅=Γht:<{~(Γ)⊢~(t)⦂~(τ)}>⊢ <{~(Γ)⊢~(t')⦂~(τ)}>Alternative `snd` has not been providedAlternative `pair` has not been providedAlternative `fst` has not been providedinductionhtgeneralizingt'with(subst_varssndt:Tmτ:TyΓ:Contextt✝:Tmτ₁✝:Tyτ₂✝:Tyt':Tmhs:<{sndt✝}>⟶t'h✝:<{∅⊢~(t✝)⦂τ₁✝×τ₂✝}>h_ih✝:∀{t':Tm},t✝⟶t'→∅=∅→<{∅⊢~(t')⦂τ₁✝×τ₂✝}>⊢ <{∅⊢~(t')⦂~(τ₂✝)}>;first-- discharge the goals where `t` doesn't step|inversionhssnd₁t:Tmτ:TyΓ:Contextt✝:Tmτ₁✝:Tyτ₂✝:Tyh✝:<{∅⊢~(t✝)⦂τ₁✝×τ₂✝}>h_ih✝:∀{t':Tm},t✝⟶t'→∅=∅→<{∅⊢~(t')⦂τ₁✝×τ₂✝}>t'✝:Tma✝:t✝⟶t'✝⊢ <{∅⊢sndt'✝⦂~(τ₂✝)}>sndPairt:Tmτ:TyΓ:Contextτ₁✝:Tyτ₂✝:Tyt':Tmv₁✝:Tma✝¹:v₁✝.IsValuea✝:t'.IsValueh✝:<{∅⊢(v₁✝,t')⦂τ₁✝×τ₂✝}>h_ih✝:∀{t'_1:Tm},<{(v₁✝,t')}>⟶t'_1→∅=∅→<{∅⊢~(t'_1)⦂τ₁✝×τ₂✝}>⊢ <{∅⊢~(t')⦂~(τ₂✝)}><;>snd₁t:Tmτ:TyΓ:Contextt✝:Tmτ₁✝:Tyτ₂✝:Tyh✝:<{∅⊢~(t✝)⦂τ₁✝×τ₂✝}>h_ih✝:∀{t':Tm},t✝⟶t'→∅=∅→<{∅⊢~(t')⦂τ₁✝×τ₂✝}>t'✝:Tma✝:t✝⟶t'✝⊢ <{∅⊢sndt'✝⦂~(τ₂✝)}>sndPairt:Tmτ:TyΓ:Contextτ₁✝:Tyτ₂✝:Tyt':Tmv₁✝:Tma✝¹:v₁✝.IsValuea✝:t'.IsValueh✝:<{∅⊢(v₁✝,t')⦂τ₁✝×τ₂✝}>h_ih✝:∀{t'_1:Tm},<{(v₁✝,t')}>⟶t'_1→∅=∅→<{∅⊢~(t'_1)⦂τ₁✝×τ₂✝}>⊢ <{∅⊢~(t')⦂~(τ₂✝)}>constructorsndPair.htt:Tmτ:TyΓ:Contextτ₁✝:Tyτ₂✝:Tyt':Tmv₁✝:Tma✝¹:v₁✝.IsValuea✝:t'.IsValueh✝:<{∅⊢(v₁✝,t')⦂τ₁✝×τ₂✝}>h_ih✝:∀{t'_1:Tm},<{(v₁✝,t')}>⟶t'_1→∅=∅→<{∅⊢~(t'_1)⦂τ₁✝×τ₂✝}>⊢ <{∅⊢~(t')⦂~(?sndPair.τ₁)}>sndPair.hst:Tmτ:TyΓ:Contextτ₁✝:Tyτ₂✝:Tyt':Tmv₁✝:Tma✝¹:v₁✝.IsValuea✝:t'.IsValueh✝:<{∅⊢(v₁✝,t')⦂τ₁✝×τ₂✝}>h_ih✝:∀{t'_1:Tm},<{(v₁✝,t')}>⟶t'_1→∅=∅→<{∅⊢~(t'_1)⦂τ₁✝×τ₂✝}>⊢ ?sndPair.τ₁<:τ₂✝sndPair.τ₁t:Tmτ:TyΓ:Contextτ₁✝:Tyτ₂✝:Tyt':Tmv₁✝:Tma✝¹:v₁✝.IsValuea✝:t'.IsValueh✝:<{∅⊢(v₁✝,t')⦂τ₁✝×τ₂✝}>h_ih✝:∀{t'_1:Tm},<{(v₁✝,t')}>⟶t'_1→∅=∅→<{∅⊢~(t'_1)⦂τ₁✝×τ₂✝}>⊢ Ty<;>snd₁.htt:Tmτ:TyΓ:Contextt✝:Tmτ₁✝:Tyτ₂✝:Tyh✝:<{∅⊢~(t✝)⦂τ₁✝×τ₂✝}>h_ih✝:∀{t':Tm},t✝⟶t'→∅=∅→<{∅⊢~(t')⦂τ₁✝×τ₂✝}>t'✝:Tma✝:t✝⟶t'✝⊢ <{∅⊢sndt'✝⦂~(?snd₁.τ₁)}>snd₁.hst:Tmτ:TyΓ:Contextt✝:Tmτ₁✝:Tyτ₂✝:Tyh✝:<{∅⊢~(t✝)⦂τ₁✝×τ₂✝}>h_ih✝:∀{t':Tm},t✝⟶t'→∅=∅→<{∅⊢~(t')⦂τ₁✝×τ₂✝}>t'✝:Tma✝:t✝⟶t'✝⊢ ?snd₁.τ₁<:τ₂✝snd₁.τ₁t:Tmτ:TyΓ:Contextt✝:Tmτ₁✝:Tyτ₂✝:Tyh✝:<{∅⊢~(t✝)⦂τ₁✝×τ₂✝}>h_ih✝:∀{t':Tm},t✝⟶t'→∅=∅→<{∅⊢~(t')⦂τ₁✝×τ₂✝}>t'✝:Tma✝:t✝⟶t'✝⊢ TysndPair.htt:Tmτ:TyΓ:Contextτ₁✝:Tyτ₂✝:Tyt':Tmv₁✝:Tma✝¹:v₁✝.IsValuea✝:t'.IsValueh✝:<{∅⊢(v₁✝,t')⦂τ₁✝×τ₂✝}>h_ih✝:∀{t'_1:Tm},<{(v₁✝,t')}>⟶t'_1→∅=∅→<{∅⊢~(t'_1)⦂τ₁✝×τ₂✝}>⊢ <{∅⊢~(t')⦂~(?sndPair.τ₁)}>sndPair.hst:Tmτ:TyΓ:Contextτ₁✝:Tyτ₂✝:Tyt':Tmv₁✝:Tma✝¹:v₁✝.IsValuea✝:t'.IsValueh✝:<{∅⊢(v₁✝,t')⦂τ₁✝×τ₂✝}>h_ih✝:∀{t'_1:Tm},<{(v₁✝,t')}>⟶t'_1→∅=∅→<{∅⊢~(t'_1)⦂τ₁✝×τ₂✝}>⊢ ?sndPair.τ₁<:τ₂✝sndPair.τ₁t:Tmτ:TyΓ:Contextτ₁✝:Tyτ₂✝:Tyt':Tmv₁✝:Tma✝¹:v₁✝.IsValuea✝:t'.IsValueh✝:<{∅⊢(v₁✝,t')⦂τ₁✝×τ₂✝}>h_ih✝:∀{t'_1:Tm},<{(v₁✝,t')}>⟶t'_1→∅=∅→<{∅⊢~(t'_1)⦂τ₁✝×τ₂✝}>⊢ Tysimp_allsndPair.τ₁t:Tmτ:TyΓ:Contextτ₁✝:Tyτ₂✝:Tyt':Tmv₁✝:Tma✝¹:v₁✝.IsValuea✝:t'.IsValueh✝:<{∅⊢(v₁✝,t')⦂τ₁✝×τ₂✝}>h_ih✝:∀{t'_1:Tm},<{(v₁✝,t')}>⟶t'_1→<{∅⊢~(t'_1)⦂τ₁✝×τ₂✝}>⊢ Ty;doneAll goals completed! 🐙|try(inversionhssnd₁t:Tmτ:TyΓ:Contextt✝:Tmτ₁✝:Tyτ₂✝:Tyh✝:<{∅⊢~(t✝)⦂τ₁✝×τ₂✝}>h_ih✝:∀{t':Tm},t✝⟶t'→∅=∅→<{∅⊢~(t')⦂τ₁✝×τ₂✝}>t'✝:Tma✝:t✝⟶t'✝⊢ <{∅⊢sndt'✝⦂~(τ₂✝)}>sndPairt:Tmτ:TyΓ:Contextτ₁✝:Tyτ₂✝:Tyt':Tmv₁✝:Tma✝¹:v₁✝.IsValuea✝:t'.IsValueh✝:<{∅⊢(v₁✝,t')⦂τ₁✝×τ₂✝}>h_ih✝:∀{t'_1:Tm},<{(v₁✝,t')}>⟶t'_1→∅=∅→<{∅⊢~(t'_1)⦂τ₁✝×τ₂✝}>⊢ <{∅⊢~(t')⦂~(τ₂✝)}>;apply_rulesusingStlcSubTypingsndPairt:Tmτ:TyΓ:Contextτ₁✝:Tyτ₂✝:Tyt':Tmv₁✝:Tma✝¹:v₁✝.IsValuea✝:t'.IsValueh✝:<{∅⊢(v₁✝,t')⦂τ₁✝×τ₂✝}>h_ih✝:∀{t'_1:Tm},<{(v₁✝,t')}>⟶t'_1→∅=∅→<{∅⊢~(t'_1)⦂τ₁✝×τ₂✝}>⊢ <{∅⊢~(t')⦂~(τ₂✝)}>;doneAll goals completed! 🐙))|appΓτ₁'τ₂'t₁'t₂h₁h₂ih₁ih₂=>appt: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')⦂~(τ₁')}>inversionhswith(try(constructorapp₂.h₁t:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₁':Tmt₂:Tmh₁:<{∅⊢~(t₁')⦂τ₂'→τ₁'}>h₂:<{∅⊢~(t₂)⦂~(τ₂')}>ih₁:∀{t':Tm},t₁'⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>t₂'✝:Tma✝¹:t₁'.IsValuea✝:t₂⟶t₂'✝⊢ <{∅⊢~(t₁')⦂~?app₂.τ₂→τ₁'}>app₂.h₂t:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₁':Tmt₂:Tmh₁:<{∅⊢~(t₁')⦂τ₂'→τ₁'}>h₂:<{∅⊢~(t₂)⦂~(τ₂')}>ih₁:∀{t':Tm},t₁'⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>t₂'✝:Tma✝¹:t₁'.IsValuea✝:t₂⟶t₂'✝⊢ <{∅⊢~(t₂'✝)⦂~(?app₂.τ₂)}>app₂.τ₂t:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₁':Tmt₂:Tmh₁:<{∅⊢~(t₁')⦂τ₂'→τ₁'}>h₂:<{∅⊢~(t₂)⦂~(τ₂')}>ih₁:∀{t':Tm},t₁'⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>t₂'✝:Tma✝¹:t₁'.IsValuea✝:t₂⟶t₂'✝⊢ Ty<;>app₂.h₁t:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₁':Tmt₂:Tmh₁:<{∅⊢~(t₁')⦂τ₂'→τ₁'}>h₂:<{∅⊢~(t₂)⦂~(τ₂')}>ih₁:∀{t':Tm},t₁'⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>t₂'✝:Tma✝¹:t₁'.IsValuea✝:t₂⟶t₂'✝⊢ <{∅⊢~(t₁')⦂~?app₂.τ₂→τ₁'}>app₂.h₂t:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₁':Tmt₂:Tmh₁:<{∅⊢~(t₁')⦂τ₂'→τ₁'}>h₂:<{∅⊢~(t₂)⦂~(τ₂')}>ih₁:∀{t':Tm},t₁'⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>t₂'✝:Tma✝¹:t₁'.IsValuea✝:t₂⟶t₂'✝⊢ <{∅⊢~(t₂'✝)⦂~(?app₂.τ₂)}>app₂.τ₂t:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₁':Tmt₂:Tmh₁:<{∅⊢~(t₁')⦂τ₂'→τ₁'}>h₂:<{∅⊢~(t₂)⦂~(τ₂')}>ih₁:∀{t':Tm},t₁'⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>t₂'✝:Tma✝¹:t₁'.IsValuea✝:t₂⟶t₂'✝⊢ Tyapply_rulesAll goals completed! 🐙;done))|appAbs_τ₂t₁h=>obtain⟨h₁,h₂⟩:=abs_arrowh₁appAbst:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₂:Tmh₂✝:<{∅⊢~(t₂)⦂~(τ₂')}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>x✝:Stringτ₂:Tyt₁:Tmh₁✝:<{∅⊢λ~x✝:τ₂.t₁⦂τ₂'→τ₁'}>ih₁:∀{t':Tm},<{λ~x✝:τ₂.t₁}>⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>h:t₂.IsValueh₁:τ₂'<:τ₂h₂:<{~(x✝→ₚτ₂)⊢~(t₁)⦂~(τ₁')}>⊢ <{∅⊢~(substx✝t₂t₁)⦂~(τ₁')}>applysubstitution_preserves_typing(τ₁:=τ₂)appAbs.htt:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₂:Tmh₂✝:<{∅⊢~(t₂)⦂~(τ₂')}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>x✝:Stringτ₂:Tyt₁:Tmh₁✝:<{∅⊢λ~x✝:τ₂.t₁⦂τ₂'→τ₁'}>ih₁:∀{t':Tm},<{λ~x✝:τ₂.t₁}>⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>h:t₂.IsValueh₁:τ₂'<:τ₂h₂:<{~(x✝→ₚτ₂)⊢~(t₁)⦂~(τ₁')}>⊢ <{~(x✝→ₚτ₂)⊢~(t₁)⦂~(τ₁')}>appAbs.hvt:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₂:Tmh₂✝:<{∅⊢~(t₂)⦂~(τ₂')}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>x✝:Stringτ₂:Tyt₁:Tmh₁✝:<{∅⊢λ~x✝:τ₂.t₁⦂τ₂'→τ₁'}>ih₁:∀{t':Tm},<{λ~x✝:τ₂.t₁}>⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>h:t₂.IsValueh₁:τ₂'<:τ₂h₂:<{~(x✝→ₚτ₂)⊢~(t₁)⦂~(τ₁')}>⊢ <{∅⊢~(t₂)⦂~(τ₂)}>·appAbs.htt:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₂:Tmh₂✝:<{∅⊢~(t₂)⦂~(τ₂')}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>x✝:Stringτ₂:Tyt₁:Tmh₁✝:<{∅⊢λ~x✝:τ₂.t₁⦂τ₂'→τ₁'}>ih₁:∀{t':Tm},<{λ~x✝:τ₂.t₁}>⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>h:t₂.IsValueh₁:τ₂'<:τ₂h₂:<{~(x✝→ₚτ₂)⊢~(t₁)⦂~(τ₁')}>⊢ <{~(x✝→ₚτ₂)⊢~(t₁)⦂~(τ₁')}>assumptionAll goals completed! 🐙·appAbs.hvt:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₂:Tmh₂✝:<{∅⊢~(t₂)⦂~(τ₂')}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>x✝:Stringτ₂:Tyt₁:Tmh₁✝:<{∅⊢λ~x✝:τ₂.t₁⦂τ₂'→τ₁'}>ih₁:∀{t':Tm},<{λ~x✝:τ₂.t₁}>⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>h:t₂.IsValueh₁:τ₂'<:τ₂h₂:<{~(x✝→ₚτ₂)⊢~(t₁)⦂~(τ₁')}>⊢ <{∅⊢~(t₂)⦂~(τ₂)}>applyHasType.subappAbs.hv.htt:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₂:Tmh₂✝:<{∅⊢~(t₂)⦂~(τ₂')}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>x✝:Stringτ₂:Tyt₁:Tmh₁✝:<{∅⊢λ~x✝:τ₂.t₁⦂τ₂'→τ₁'}>ih₁:∀{t':Tm},<{λ~x✝:τ₂.t₁}>⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>h:t₂.IsValueh₁:τ₂'<:τ₂h₂:<{~(x✝→ₚτ₂)⊢~(t₁)⦂~(τ₁')}>⊢ <{∅⊢~(t₂)⦂~(?appAbs.hv.τ₁)}>appAbs.hv.hst:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₂:Tmh₂✝:<{∅⊢~(t₂)⦂~(τ₂')}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>x✝:Stringτ₂:Tyt₁:Tmh₁✝:<{∅⊢λ~x✝:τ₂.t₁⦂τ₂'→τ₁'}>ih₁:∀{t':Tm},<{λ~x✝:τ₂.t₁}>⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>h:t₂.IsValueh₁:τ₂'<:τ₂h₂:<{~(x✝→ₚτ₂)⊢~(t₁)⦂~(τ₁')}>⊢ ?appAbs.hv.τ₁<:τ₂appAbs.hv.τ₁t:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₂:Tmh₂✝:<{∅⊢~(t₂)⦂~(τ₂')}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>x✝:Stringτ₂:Tyt₁:Tmh₁✝:<{∅⊢λ~x✝:τ₂.t₁⦂τ₂'→τ₁'}>ih₁:∀{t':Tm},<{λ~x✝:τ₂.t₁}>⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>h:t₂.IsValueh₁:τ₂'<:τ₂h₂:<{~(x✝→ₚτ₂)⊢~(t₁)⦂~(τ₁')}>⊢ Ty<;>appAbs.hv.htt:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₂:Tmh₂✝:<{∅⊢~(t₂)⦂~(τ₂')}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>x✝:Stringτ₂:Tyt₁:Tmh₁✝:<{∅⊢λ~x✝:τ₂.t₁⦂τ₂'→τ₁'}>ih₁:∀{t':Tm},<{λ~x✝:τ₂.t₁}>⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>h:t₂.IsValueh₁:τ₂'<:τ₂h₂:<{~(x✝→ₚτ₂)⊢~(t₁)⦂~(τ₁')}>⊢ <{∅⊢~(t₂)⦂~(?appAbs.hv.τ₁)}>appAbs.hv.hst:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₂:Tmh₂✝:<{∅⊢~(t₂)⦂~(τ₂')}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>x✝:Stringτ₂:Tyt₁:Tmh₁✝:<{∅⊢λ~x✝:τ₂.t₁⦂τ₂'→τ₁'}>ih₁:∀{t':Tm},<{λ~x✝:τ₂.t₁}>⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>h:t₂.IsValueh₁:τ₂'<:τ₂h₂:<{~(x✝→ₚτ₂)⊢~(t₁)⦂~(τ₁')}>⊢ ?appAbs.hv.τ₁<:τ₂appAbs.hv.τ₁t:Tmτ:TyΓ:Contextτ₁':Tyτ₂':Tyt₂:Tmh₂✝:<{∅⊢~(t₂)⦂~(τ₂')}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₂')}>x✝:Stringτ₂:Tyt₁:Tmh₁✝:<{∅⊢λ~x✝:τ₂.t₁⦂τ₂'→τ₁'}>ih₁:∀{t':Tm},<{λ~x✝:τ₂.t₁}>⟶t'→∅=∅→<{∅⊢~(t')⦂τ₂'→τ₁'}>h:t₂.IsValueh₁:τ₂'<:τ₂h₂:<{~(x✝→ₚτ₂)⊢~(t₁)⦂~(τ₁')}>⊢ Tyapply_rulesusingStlcSubTypingAll goals completed! 🐙|iteΓt₁t₂t₃τh₁h₂h₃ih₁ih₂ih₃=>itet:Tmτ✝:TyΓ:Contextt₁:Tmt₂:Tmt₃:Tmτ:Tyt':Tmhs:<{ift₁thent₂elset₃}>⟶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')⦂~(τ)}>inversionhswith(try(constructorifFalse.htt: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₃)⦂~(?ifFalse.τ₁)}>ifFalse.hst: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}>⊢ ?ifFalse.τ₁<:τifFalse.τ₁t:Tmτ✝:TyΓ:Contextt₂:Tmt₃:Tmτ:Tyh₂:<{∅⊢~(t₂)⦂~(τ)}>h₃:<{∅⊢~(t₃)⦂~(τ)}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ)}>ih₃:∀{t':Tm},t₃⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ)}>h₁:<{∅⊢false⦂Bool}>ih₁:∀{t':Tm},<{false}>⟶t'→∅=∅→<{∅⊢~(t')⦂Bool}>⊢ Ty<;>ifFalse.htt: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₃)⦂~(?ifFalse.τ₁)}>ifFalse.hst: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}>⊢ ?ifFalse.τ₁<:τifFalse.τ₁t:Tmτ✝:TyΓ:Contextt₂:Tmt₃:Tmτ:Tyh₂:<{∅⊢~(t₂)⦂~(τ)}>h₃:<{∅⊢~(t₃)⦂~(τ)}>ih₂:∀{t':Tm},t₂⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ)}>ih₃:∀{t':Tm},t₃⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ)}>h₁:<{∅⊢false⦂Bool}>ih₁:∀{t':Tm},<{false}>⟶t'→∅=∅→<{∅⊢~(t')⦂Bool}>⊢ Tysolve_by_elimusingStlcSubEvalAll goals completed! 🐙))|subΓt₁τ₁τ₂hthsih=>subt:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyhs✝:τ₁<:τ₂t':Tmhs:t₁⟶t'ht:<{∅⊢~(t₁)⦂~(τ₁)}>ih:∀{t':Tm},t₁⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₁)}>⊢ <{∅⊢~(t')⦂~(τ₂)}>applyHasType.subsub.htt:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyhs✝:τ₁<:τ₂t':Tmhs:t₁⟶t'ht:<{∅⊢~(t₁)⦂~(τ₁)}>ih:∀{t':Tm},t₁⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₁)}>⊢ <{∅⊢~(t')⦂~(?sub.τ₁)}>sub.hst:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyhs✝:τ₁<:τ₂t':Tmhs:t₁⟶t'ht:<{∅⊢~(t₁)⦂~(τ₁)}>ih:∀{t':Tm},t₁⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₁)}>⊢ ?sub.τ₁<:τ₂sub.τ₁t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyhs✝:τ₁<:τ₂t':Tmhs:t₁⟶t'ht:<{∅⊢~(t₁)⦂~(τ₁)}>ih:∀{t':Tm},t₁⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₁)}>⊢ Ty<;>sub.htt:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyhs✝:τ₁<:τ₂t':Tmhs:t₁⟶t'ht:<{∅⊢~(t₁)⦂~(τ₁)}>ih:∀{t':Tm},t₁⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₁)}>⊢ <{∅⊢~(t')⦂~(?sub.τ₁)}>sub.hst:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyhs✝:τ₁<:τ₂t':Tmhs:t₁⟶t'ht:<{∅⊢~(t₁)⦂~(τ₁)}>ih:∀{t':Tm},t₁⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₁)}>⊢ ?sub.τ₁<:τ₂sub.τ₁t:Tmτ:TyΓ:Contextt₁:Tmτ₁:Tyτ₂:Tyhs✝:τ₁<:τ₂t':Tmhs:t₁⟶t'ht:<{∅⊢~(t₁)⦂~(τ₁)}>ih:∀{t':Tm},t₁⟶t'→∅=∅→<{∅⊢~(t')⦂~(τ₁)}>⊢ Tysolve_by_elimusingStlcSubTypingAll goals completed! 🐙-- FILL IN HERE