diff --git a/out/Maps.md b/out/Maps.md index eb38d314..62703ef3 100644 --- a/out/Maps.md +++ b/out/Maps.md @@ -32,7 +32,8 @@ much difference, though, because we've been careful to name our own definitions and theorems the same as their counterparts in the standard library, wherever they overlap. -
{% raw %} +Documentation for the standard library can be found at+ open) -{% endraw %}+ +
{% raw %} +We recall a standard fact of logic. -+ dataId -{% endraw %}+ +
{% raw %} +Using the above, we can decide equality of two identifiers by deciding equality on the underlying strings. -+ contrapositive) -{% endraw %}+ +
{% raw %} +## Total Maps @@ -727,7 +735,8 @@ We build partial maps in two steps. First, we define a type of _total maps_ that return a default value when we look up a key that is not present in the map. -+ _≟_refl -{% endraw %}+ +
{% raw %} +Intuitively, a total map over anfi element type `A` _is_ just a function that can be used to look up ids, yielding `A`s. -+ TotalMapA -{% endraw %}+ +
{% raw %} +The function `always` yields a total map given a default element; this map always returns the default element when applied to any id. -+ modulewhere -{% endraw %}+ +
{% raw %} +More interesting is the update function, which (as before) takes a map `ρ`, a key `x`, and a value `v` and returns a new map that takes `x` to `v` and takes every other key to whatever `ρ` does. -+ alwaysv -{% endraw %}+ +
{% raw %} +This definition is a nice example of higher-order programming. The update function takes a _function_ `ρ` and yields a new @@ -1044,7 +1060,8 @@ function that behaves like the desired map. For example, we can build a map taking ids to naturals, where `x` maps to 42, `y` maps to 69, and every other key maps to 0, as follows: -+ infixly -{% endraw %}+ +
{% raw %} +This completes the definition of total maps. Note that we don't need to define a `find` operation because it is just function @@ -1327,7 +1345,8 @@ the lemmas! #### Exercise: 1 star, optional (apply-always) The `always` map returns its default element for all keys: -+ modulerefl -{% endraw %}+ +
{% raw %} ++ postulatev -{% endraw %}+ +
{% raw %} ++ apply-always′refl -{% endraw %}+ +
{% raw %} ++ postulatev -{% endraw %}+ +
{% raw %} ++ update-eq′) -{% endraw %}+ +
{% raw %} +For the following lemmas, since maps are represented by functions, to show two maps equal we will need to postulate extensionality. -+ update-neqrefl -{% endraw %}+ +
{% raw %} +#### Exercise: 2 stars, optional (update-shadow) If we update a map `ρ` at a key `x` with a value `v` and then @@ -2230,7 +2260,8 @@ resulting map behaves the same (gives the same result when applied to any key) as the simpler map obtained by performing just the second update on `ρ`: -+ postulateρ′ -{% endraw %}+ +
{% raw %} ++ postulate) -{% endraw %}+ +
{% raw %} ++ update-shadow′x≢y -{% endraw %}+ +
{% raw %} ++ postulateρ -{% endraw %}+ +
{% raw %} ++ update-same′refl -{% endraw %}+ +
{% raw %} ++ postulate) -{% endraw %}+ +
{% raw %} +And a slightly different version of the same proof. -+ update-permute′)) -{% endraw %}+ +
{% raw %} ++ update-permute′′)) -{% endraw %}+ +
{% raw %} +We now lift all of the basic lemmas about total maps to partial maps. -+ PartialMap) -{% endraw %}-{% raw %} ++ ++ modulewhere -{% endraw %}-{% raw %} ++ ++ ∅nothing -{% endraw %}-{% raw %} ++ ++ infixl) -{% endraw %}+ +
{% raw %} ++ +We will also need the following basic facts about the `Maybe` type. + ++ apply-∅x -{% endraw %}-{% raw %} ++ ++ update-eq) -{% endraw %}-{% raw %} ++ ++ update-neqx≢y -{% endraw %}-{% raw %} ++ ++ update-shadow) -{% endraw %}-{% raw %} ++ ++ update-samex -{% endraw %}-{% raw %} ++ ++ update-permutex≢y -{% endraw %}+ +
+ + just≢nothing : ∀ {X : Set} → ∀ {x : X} → ¬ (_≡_ {A = Maybe X} (just x) nothing) + just≢nothing () + + just-injective : ∀ {X : Set} {x y : X} → _≡_ {A = Maybe X} (just x) (just y) → x ≡ y + just-injective refl = refl + +diff --git a/out/Stlc.md b/out/Stlc.md index 069d4a8e..dc5c5960 100644 --- a/out/Stlc.md +++ b/out/Stlc.md @@ -7,7 +7,7 @@ permalink : /Stlc The _lambda-calculus_, first published by the logician Alonzo Church in 1932, is a core calculus with only three syntactic constructs: variables, abstraction, and application. It embodies the concept of -_functional abstraction_, which shows up in almsot every programming +_functional abstraction_, which shows up in almost every programming language in some form (as functions, procedures, or methods). The _simply-typed lambda calculus_ (or STLC) is a variant of the lambda calculus published by Church in 1940. It has just the three @@ -108,162 +108,174 @@ lists, records, subtyping, and mutable state. >∅); renaming (_,_↦_just-injective) torenaming (_,_↦_ to _,_∶_) open import Data.Nat using (ℕ) -open import Data.Nat using (ℕ) +open import Data.Maybe using (Maybe; just; nothing) open import Relation.Nullary using (Dec; yes; no) -open import no; ¬_) +open import Relation.Binary.PropositionalEquality using (_≡_; _≢_; refl) @@ -289,79 +301,79 @@ And here it is formalised in Agda.
-infixr 20 _⇒_ data Type : Set where - _⇒_ : Type: →Set Typewhere → Type 𝔹_⇒_ : Type → Type → Type + 𝔹 : Type @@ -382,7 +394,7 @@ and three are for the base type, booleans: Abstraction is also called lambda abstraction, and is the construct from which the calculus takes its name. -With the exception of variables, each construct either constructs +With the exception of variables, each term form either constructs a value of a given type (abstractions yield functions, true and false yield booleans) or deconstructs it (applications use functions, conditionals use booleans). We will see this again when we come @@ -397,134 +409,113 @@ And here it is formalised in Agda.-infixl 20 _·_ infix 15 λ[_∶_]_ infix 15 if_then_else_ data Term : Set where ` : Id → Term - λ[_∶_]_ : Id → → Type → Term → Term _·_λ[_∶_]_ : Id → Type :→ Term → Term → Term _·_ : Term → Term → Term + true : Term - false : Term Term if_then_else_false : Term + if_then_else_ →: Term → Term → Term → Term @@ -658,246 +670,246 @@ and applies the function to the boolean twice.-f x y : Id -f = id 0 - x = id 1y : Id yf = id 20 +x = id 1 +y = id 2 not two : Term -not = λ[ x ∶: 𝔹 ] (if `Term +not x= λ[ thenx false∶ else𝔹 ] (if true) -two` = λ[x fthen ∶false else 𝔹 ⇒ 𝔹true) +two ] = λ[ x ∶ 𝔹 ] ` f ·∶ (`𝔹 ⇒ 𝔹 ] fλ[ · ` x ∶ 𝔹 ] ` f · (` f · ` x) @@ -909,21 +921,12 @@ and applies the function to the boolean twice. In an abstraction `λ[ x ∶ A ] N` we call `x` the _bound_ variable and `N` the _body_ of the abstraction. One of the most important aspects of lambda calculus is that names of bound variables are -irrelevant. Thus the two terms +irrelevant. Thus the four terms - λ[ f ∶ 𝔹 ⇒ 𝔹 ] λ[ x ∶ 𝔹 ] ` f · (` f · ` x) - -and - - λ[ g ∶ 𝔹 ⇒ 𝔹 ] λ[ y ∶ 𝔹 ] ` g · (` g · ` y) - -and - - λ[ fred ∶ 𝔹 ⇒ 𝔹 ] λ[ xander ∶ 𝔹 ] ` fred · (` fred · ` xander) - -and even - - λ[ x ∶ 𝔹 ⇒ 𝔹 ] λ[ f ∶ 𝔹 ] ` x · (` x · ` f) +* `` λ[ f ∶ 𝔹 ⇒ 𝔹 ] λ[ x ∶ 𝔹 ] ` f · (` f · ` x) `` +* `` λ[ g ∶ 𝔹 ⇒ 𝔹 ] λ[ y ∶ 𝔹 ] ` g · (` g · ` y) `` +* `` λ[ fred ∶ 𝔹 ⇒ 𝔹 ] λ[ xander ∶ 𝔹 ] ` fred · (` fred · ` xander) `` +* `` λ[ x ∶ 𝔹 ⇒ 𝔹 ] λ[ f ∶ 𝔹 ] ` x · (` x · ` f) `` are all considered equivalent. This equivalence relation is sometimes called _alpha renaming_. @@ -981,369 +984,369 @@ to be weaker than application. For instance,-ex₁ : (𝔹 ⇒ 𝔹) ⇒ 𝔹 ⇒ 𝔹 ≡⇒ (𝔹) ⇒ 𝔹) ⇒ (𝔹 ≡ ⇒ (𝔹) ⇒ 𝔹) ⇒ (𝔹 ⇒ 𝔹) ex₁ = refl ex₂ : two · not · true ≡· (two · not) · true -ex₂ ≡ (two · not=) · true +ex₂ = refl ex₃ : λ[ f ∶ 𝔹 ⇒ 𝔹: ] λ[ f x∶ ∶𝔹 𝔹⇒ ]𝔹 `] fλ[ ·x (`∶ f𝔹 ·] ` x) - ≡f · (` f · (λ[ f ∶ 𝔹 ⇒ 𝔹 ] (λ[ x ∶ 𝔹 ] (` x) + ≡ (λ[ f ∶ 𝔹 ⇒ 𝔹 ] (λ[ ·x ∶ 𝔹 ] (` f · ` f · (` f · ` x)))) ex₃ = refl @@ -1395,130 +1398,130 @@ The predicate `Value M` holds if term `M` is a value.-data Value : Term → SetValue : Term → Set where value-λ : ∀ {x A : N}∀ → Value{x (λ[ x ∶ A ] N} → Value (λ[ x ∶ A ] N) - value-true : Value true value-false value-true : Value true + value-false : Value false @@ -1591,646 +1594,646 @@ Here is the formal definition in Agda.-_[_:=_] : Term → Id → Term → Term (` x′) [ x := V ]x′) with[ x ≟:= x′ -...V |] with yesx ≟ _ = Vx′ ... | no yes _ = ` x′V (λ[... | no _ = ` x′ +(λ[ ∶ A′ ] N′) [x′ x∶ :=A′ V] ]N′) with[ x ≟:= x′ -...V |] with yesx ≟ _ = λ[x′ +... x′| ∶yes A′_ ]= N′λ[ x′ ∶ A′ ] N′ ... | no _ = λ[ x′| ∶no A′ _ ]= (N′λ[ [x′ x∶ :=A′ V] ]) -(L′N′ ·[ M′)x := V [ x :=]) +(L′ V· ] M′=) (L′ [ x := xV := V ]) · = (M′L′ [ x := xV :=]) V· (M′ [ x := V ]) (true) [ x := V ] =) true -(false[ x := V ] )= [ x := V ] = falsetrue (iffalse) L′[ x := V ] = thenfalse +(if M′ elseL′ N′)then [ xM′ := Velse ] N′=) - if (L′[ x := V [] x= := V + if ])(L′ then[ x (M′:= [V x]) := Vthen ])(M′ else[ x (N′:= [V x]) := Velse (N′ [ x := V ]) @@ -2262,666 +2265,666 @@ Here is confirmation that the examples above are correct.-ex₁₁ : ` f [ f := not: ` ]f ≡[ not f := not ] ≡ not ex₁₁ = refl - -ex₁₂ := true [ f := not ] ≡ true -ex₁₂ = refl ex₁₃ex₁₂ : true [ f := not ] ≡ true +ex₁₂ := (` f · true) [ f := not ] ≡ not · true -ex₁₃ = refl ex₁₄ex₁₃ : (` f · true) [ f := not ] ≡ not · true +ex₁₃ := (` frefl + +ex₁₄ ·: (` f · true)) [(` f :=· not ]true)) ≡[ notf ·:= (not ] ·≡ true)not · -ex₁₄ (not =· refltrue) - ex₁₅ex₁₄ := refl + +ex₁₅ : (λ[ x ∶ 𝔹 ] ` f · (` f𝔹 ·] ` x))f · [(` f :=· not` ]x)) ≡[ λ[f x:= ∶ 𝔹not ] not≡ ·λ[ (notx ∶ 𝔹 ·] not · (not · ` x) ex₁₅ = refl - -ex₁₆ := (λ[ y ∶ 𝔹 ] ` y) [ x := true ] ≡ λ[ y ∶ 𝔹 ] ` y -ex₁₆ = refl ex₁₇ex₁₆ : (λ[ y ∶ 𝔹 ] ` y) [ x := true ] ≡ λ[ y ∶ 𝔹 ] ` y +ex₁₆ := refl + +ex₁₇ : (λ[ x ∶ 𝔹 ] ` x) [x x∶ := true ] ≡ λ[ x ∶ 𝔹 ] ` x) [ x := true ] `≡ λ[ x -ex₁₇ ∶ =𝔹 ] ` x +ex₁₇ = refl @@ -2950,8 +2953,8 @@ conditional, we first reduce the condition until it becomes a value; if the condition is true the conditional reduces to the first branch and if false it reduces to the second branch.a -In an informal presentation of the formal semantics, the rules -are written as follows. +In an informal presentation of the formal semantics, +the rules for reduction are written as follows. L ⟹ L′ --------------- ξ·₁ @@ -2991,571 +2994,573 @@ a deconstructor, in our case `λ` and `·`, or We give them names starting with the Greek letter beta, `β`, and indeed such rules are traditionally called beta rules. +Here are the above rules formalised in Agda. +-infix 10 _⟹_ data _⟹_ : Term → Term → Set where - ξ·₁ : ∀ {L L′ M} → - L ⟹ L′ → - L · M ⟹_⟹_ L′ · M - ξ·₂ : ∀Term {V→ MTerm → Set M′} →where - Valueξ·₁ : ∀ V{L L′ M} → M ⟹ M′ →L ⟹ L′ → VL · M ⟹ V · M′ L′ · M βλ· : ∀ {xξ·₂ A: N∀ {V} →M ValueM′} V → (λ[Value V x→ ∶ A ] + M N)⟹ ·M′ V→ ⟹ N [ + V x· :=M ⟹ V ]· M′ ξif : ∀βλ· : ∀ {Lx L′A M N} V} → - L ⟹Value L′V → + > if(λ[ Lx then∶ MA else] N) · V ⟹ N ⟹[ ifx L′:= thenV M else N] βif-trueξif : ∀ {L L′ M N} → + L N} → - if true then M else N ⟹ L′ → + if L then M - βif-false else N ⟹ if L′ then :M ∀ {Melse N} → - ifβif-true false: then∀ {M N} M→ else N + if ⟹true then M else N ⟹ M + βif-false : ∀ {M N} → + if false then M else N ⟹ N @@ -3625,189 +3630,189 @@ Here it is formalised in Agda.-infix 10 _⟹*_ infixr 2 _⟹⟨_⟩_ infix 3 _∎ data _⟹*_ : Term → Term → Set where - _∎ : ∀ M → M ⟹* M - _⟹⟨_⟩_ : ∀ L {M N} → L_⟹*_ ⟹: MTerm → M ⟹* N → LTerm ⟹*→ Set where + _∎ : ∀ M → M ⟹* M + _⟹⟨_⟩_ : ∀ L {M N} → L ⟹ M → M ⟹* N → L ⟹* N @@ -3827,477 +3832,477 @@ out example reductions in an appealing way.-reduction₁ : not · true ⟹* false reduction₁ = not · true - ⟹⟨ βλ· value-true ⟩ - if true then false else true - ⟹⟨ βif-true ⟩ - falsetrue ⟹⟨ βλ· value-true ⟩ + if true then false else true + ⟹⟨ βif-true ⟩ + false + ∎ reduction₂ : two · not · true ⟹* true -reduction₂ = - two · not · true - ⟹⟨ ξ·₁ (βλ· value-λ) ⟩ - (λ[ x· true ⟹* ∶ 𝔹 ] not · (not · ` x)) · true - ⟹⟨reduction₂ βλ· value-true ⟩= two · not · true + ⟹⟨ ξ·₁ (βλ· value-λ) ·⟩ (not · true) - ⟹⟨(λ[ ξ·₂x ∶ 𝔹 ] not · value-λ (βλ·not · ` x)) value-true)· true + ⟹⟨ βλ· value-true ⟩ not · (if true then falsenot else true) - ⟹⟨ ξ·₂ value-λ βif-true ⟩ - not · falsetrue) ⟹⟨ ξ·₂ value-λ (βλ· value-falsevalue-true) ⟩ not · (if false then false else true then false else true) ⟹⟨ βif-falseξ·₂ value-λ βif-true ⟩ + not · false - true⟹⟨ βλ· value-false ⟩ + if false then false else true ⟹⟨ βif-false ⟩ + true + ∎ @@ -4327,915 +4332,990 @@ In general, we use typing _judgements_ of the form Γ ⊢ M ∶ A which asserts in type environment `Γ` that term `M` has type `A`. -Here `Γ` provides types for all the free variables in `M`. +Environment `Γ` provides types for all the free variables in `M`. Here are three examples. +* `` ∅ , f ∶ 𝔹 ⇒ 𝔹 , x ∶ 𝔹 ⊢ ` f · (` f · ` x) ∶ 𝔹 `` +* `` ∅ , f ∶ 𝔹 ⇒ 𝔹 ⊢ (λ[ x ∶ 𝔹 ] ` f · (` f · ` x)) ∶ 𝔹 ⇒ 𝔹 `` * `` ∅ ⊢ (λ[ f ∶ 𝔹 ⇒ 𝔹 ] λ[ x ∶ 𝔹 ] ` f · (` f · ` x)) ∶ (𝔹 ⇒ 𝔹) ⇒ 𝔹 ⇒ 𝔹 `` -* `` ∅ , f ∶ 𝔹 ⇒ 𝔹 ⊢ (λ[ x ∶ 𝔹 ] ` f · (` f · ` x)) ∶ 𝔹 ⇒ 𝔹 `` - -* `` ∅ , f ∶ 𝔹 ⇒ 𝔹 , x ∶ 𝔹 ⊢ ` f · (` f · ` x) ∶ 𝔹 `` - -Environments are maps from free variables to types, built using `∅` +Environments are partial maps from identifiers to types, built using `∅` for the empty map, and `Γ , x ∶ A` for the map that extends environment `Γ` by mapping variable `x` to type `A`. +In an informal presentation of the formal semantics, +the rules for typing are written as follows. + + Γ x ≡ A + ----------- Ax + Γ ⊢ ` x ∶ A + + Γ , x ∶ A ⊢ N ∶ B + ------------------------ ⇒-I + Γ ⊢ λ[ x ∶ A ] N ∶ A ⇒ B + + Γ ⊢ L ∶ A ⇒ B + Γ ⊢ M ∶ A + -------------- ⇒-E + Γ ⊢ L · M ∶ B + + ------------- 𝔹-I₁ + Γ ⊢ true ∶ 𝔹 + + -------------- 𝔹-I₂ + Γ ⊢ false ∶ 𝔹 + + Γ ⊢ L : 𝔹 + Γ ⊢ M ∶ A + Γ ⊢ N ∶ A + -------------------------- 𝔹-E + Γ ⊢ if L then M else N ∶ A + +As we will show later, the rules are deterministic, in that +at most one rule applies to every term. + +The proof rules come in pairs, with rules to introduce and to +eliminate each connective, labeled `-I` and `-E`, respectively. As we +read the rules from top to bottom, introduction and elimination rules +do what they say on the tin: the first _introduces_ a formula for the +connective, which appears in the conclusion but not in the premises; +while the second _eliminates_ a formula for the connective, which appears in +a premise but not in the conclusion. An introduction rule describes +how to construct a value of the type (abstractions yield functions, +true and false yield booleans), while an elimination rule describes +how to deconstruct a value of the given type (applications use +functions, conditionals use booleans). + +Here are the above rules formalised in Agda.-Context : Set Context = PartialMap Type infix 10 _⊢_∶_ data _⊢_∶_ : Context → Term → Type → Set where Ax : ∀ {Γ x A} → Γ x ≡ just A → Γ ⊢ ` x ∶ A ⇒-I : ∀ {Γ x N A B} → Γ , x ∶ A ⊢ N ∶ B → Γ ⊢ λ[ x ∶ A ] N ∶ A ⇒ B ⇒-E : ∀ {Γ L M A B} → Γ ⊢ L ∶ A ⇒ B → Γ ⊢ M ∶ A → Γ ⊢ L · M ∶ B 𝔹-I₁ : ∀ {Γ} → Γ ⊢ true ∶ 𝔹 𝔹-I₂ : ∀ {Γ} → Γ ⊢ false ∶ 𝔹 𝔹-E : ∀ {Γ L M N A} → Γ ⊢ L ∶ 𝔹 → Γ ⊢ M ∶ A → Γ ⊢ N ∶ A → Γ ⊢ if L then M else N ∶ A-## Example type derivations +#### Example type derivations + +Here are a couple of typing examples. First, here is how +they would be written in an informal description of the +formal semantics. + +Derivation of `not`: + + ------------ Ax ------------- 𝔹-I₂ ------------- 𝔹-I₁ + Γ₀ ⊢ ` x ∶ 𝔹 Γ₀ ⊢ false ∶ 𝔹 Γ₀ ⊢ true ∶ 𝔹 + ------------------------------------------------------ 𝔹-E + Γ₀ ⊢ if ` x then false else true ∶ 𝔹 + --------------------------------------------------- ⇒-I + ∅ ⊢ λ[ x ∶ 𝔹 ] if ` x then false else true ∶ 𝔹 ⇒ 𝔹 + +where `Γ₀ = ∅ , x ∶ 𝔹`. + +Derivation of `two`: + ----------------- Ax ------------ Ax + Γ₂ ⊢ ` f ∶ 𝔹 ⇒ 𝔹 Γ₂ ⊢ ` x ∶ 𝔹 + ----------------- Ax ------------------------------------- ⇒-E + Γ₂ ⊢ ` f ∶ 𝔹 ⇒ 𝔹 Γ₂ ⊢ ` f · ` x ∶ 𝔹 + ------------------------------------------- ⇒-E + Γ₂ ⊢ ` f · (` f · ` x) ∶ 𝔹 + ------------------------------------------ ⇒-I + Γ₁ ⊢ λ[ x ∶ 𝔹 ] ` f · (` f · ` x) ∶ 𝔹 ⇒ 𝔹 + ---------------------------------------------------------- ⇒-I + ∅ ⊢ λ[ f ∶ 𝔹 ⇒ 𝔹 ] λ[ x ∶ 𝔹 ] ` f · (` f · ` x) ∶ 𝔹 ⇒ 𝔹 + +where `Γ₁ = ∅ , f ∶ 𝔹 ⇒ 𝔹` and `Γ₂ = ∅ , f ∶ 𝔹 ⇒ 𝔹 , x ∶ 𝔹`. + +Here are the above derivations formalised in Agda.-typing₁ : ∅ ⊢ not ∶ 𝔹 ⇒ 𝔹 typing₁ = ⇒-I (𝔹-E (Ax refl) 𝔹-I₂ 𝔹-I₁) typing₂ : ∅ ⊢ two ∶ (𝔹 ⇒ 𝔹) ⇒ 𝔹 ⇒ 𝔹 typing₂ = ⇒-I (⇒-I (⇒-E (Ax refl) (⇒-E (Ax refl) (Ax refl))))+## Interaction with Agda + Construction of a type derivation is best done interactively. -We start with the declaration: +Start with the declaration: typing₁ : ∅ ⊢ not ∶ 𝔹 ⇒ 𝔹 typing₁ = ? @@ -5269,4 +5349,275 @@ hole. After filling in all holes, the term is as above. The entire process can be automated using Agsy, invoked with C-c C-a. +#### Non-examples + +We can also show that terms are _not_ typeable. +For example, here is a formal proof that it is not possible +to type the term `` λ[ x ∶ 𝔹 ] λ[ y ∶ 𝔹 ] ` x · ` y ``. +In other words, no type `A` is the type of this term. + ++ +contradiction : ∀ {A B} → ¬ (𝔹 ≡ A ⇒ B) +contradiction () + +notyping : ∀ {A} → ¬ (∅ ⊢ λ[ x ∶ 𝔹 ] λ[ y ∶ 𝔹 ] ` x · ` y ∶ A) +notyping (⇒-I (⇒-I (⇒-E (Ax Γx) (Ax Γy)))) = contradiction (just-injective Γx) + ++ +#### Quiz + +For each of the following, given a type `A` for which it is derivable, +or explain why there is no such `A`. + +1. `` ∅ , y ∶ A ⊢ λ[ x ∶ 𝔹 ] ` x ∶ 𝔹 ⇒ 𝔹 `` +2. `` ∅ ⊢ λ[ y ∶ 𝔹 ⇒ 𝔹 ] λ[ x ∶ 𝔹 ] ` y · ` x ∶ A `` +3. `` ∅ ⊢ λ[ y ∶ 𝔹 ⇒ 𝔹 ] λ[ x ∶ 𝔹 ] ` x · ` y ∶ A `` +4. `` ∅ , x ∶ A ⊢ λ[ y : 𝔹 ⇒ 𝔹 ] `y · `x : A `` + +For each of the following, give type `A`, `B`, and `C` for which it is derivable, +or explain why there are no such types. + +1. `` ∅ ⊢ λ[ y ∶ 𝔹 ⇒ 𝔹 ⇒ 𝔹 ] λ[ x ∶ 𝔹 ] ` y · ` x ∶ A `` +2. `` ∅ , x ∶ A ⊢ x · x ∶ B `` +3. `` ∅ , x ∶ A , y ∶ B ⊢ λ[ z ∶ C ] ` x · (` y · ` z) ∶ D `` + + diff --git a/out/StlcProp.md b/out/StlcProp.md index e5da2069..9085c13e 100644 --- a/out/StlcProp.md +++ b/out/StlcProp.md @@ -351,60 +351,73 @@ theorem. >update-permute); renamingjust≢nothing; (_,_↦_ to _,_∶_just-injective) -openrenaming import Stlc -import Data.Nat using (ℕ_,_↦_ to _,_∶_) +open import Stlc +import Data.Nat using (ℕ) @@ -421,404 +434,404 @@ while for boolean types they are values `true` and `false`.-data canonical_for_ : Term → Type → Set where - canonical-λ : ∀ {x A N B}: Term → canonicalType (λ[→ xSet ∶ A ] N) for (A ⇒ B)where canonical-truecanonical-λ : ∀ {x A N B} → canonical true(λ[ x ∶ A for] 𝔹N) for (A ⇒ B) canonical-falsecanonical-true : canonical false forcanonical true for 𝔹 - -canonical-forms : ∀ {L A}canonical-false →: ∅ ⊢ L ∶ Acanonical →false Value Lfor →𝔹 + +canonical-forms canonical: ∀ {L for A -canonical-forms} (Ax→ ())∅ () -canonical-forms⊢ L ∶ A → Value L → canonical (⇒-IL ⊢N)for value-λ = canonical-λA canonical-forms (⇒-EAx ⊢L()) ⊢M) () canonical-forms (⇒-I ⊢N) value-λ = canonical-λ +canonical-forms (⇒-E ⊢L ⊢M) () +canonical-forms 𝔹-I₁ value-true = canonical-true -canonical-forms 𝔹-I₂ value-false = canonical-false canonical-forms (𝔹-E𝔹-I₂ value-false = canonical-false +canonical-forms (𝔹-E ⊢L ⊢M ⊢N) () @@ -832,191 +845,191 @@ step or it is a value.-data Progress : Term → Set where - steps : ∀ {M N} → M ⟹ N → Progress M → Set where done steps : ∀ {M} → Value {M N} → Progress M ⟹ N → Progress M + done : ∀ {M} → Value M → Progress M progress : ∀ {M A} → ∅ ⊢ M ∶ A → Progress M @@ -1073,451 +1086,451 @@ This completes the proof.-progress (Ax ()) -progress (⇒-I ⊢N) = done value-λ -progress (⇒-E ⊢L ⊢M) with progress ⊢L()) ...progress | steps L⟹L′ = steps (ξ·₁⇒-I ⊢N) = done value-λ +progress (⇒-E ⊢L L⟹L′⊢M) with progress ⊢L ... | donesteps valueL with progressL⟹L′ ⊢M -... | steps M⟹M′ = steps (ξ·₂ξ·₁ valueL M⟹M′L⟹L′) ... | done valueM with canonical-forms ⊢L valueL with progress ⊢M ... | steps M⟹M′ = steps (ξ·₂ valueL M⟹M′) +... canonical-λ| =done valueM stepswith (βλ·canonical-forms valueM)⊢L valueL progress 𝔹-I₁ =... done value-true -progress 𝔹-I₂ = done value-false -progress (𝔹-E ⊢L ⊢M ⊢N) with progress ⊢L -... | stepscanonical-λ L⟹L′ = steps (βλ· valueM) +progress 𝔹-I₁ = done value-true +progress 𝔹-I₂ = done value-false +progress steps (ξif𝔹-E ⊢L ⊢M L⟹L′⊢N) -... | done valueL with canonical-formsprogress ⊢L valueL ... | steps L⟹L′ = steps (ξif L⟹L′) +... canonical-true = steps βif-true -... | done valueL with canonical-forms ⊢L canonical-falsevalueL +... | canonical-true = steps βif-true +... | canonical-false = steps βif-false @@ -1538,68 +1551,68 @@ instead of induction on typing derivations.-postulate progress′ : ∀ M {A} → ∅ ⊢ M ∶ A → Progress M @@ -1661,598 +1674,598 @@ Formally:-data _∈_ : Id → Term → Set where - free-` : ∀ {x} → x ∈ ` x - free-λ : ∀ {x y A N} → y ≢ x → x ∈ N → x ∈ (λ[ y ∶ A ] N)where free-·₁ free-` : ∀ {x} → x ∈ ` x + free-λ : ∀ {x y A N} {→ y ≢ x L M} → x ∈ LN → x ∈ (Lλ[ ·y M)∶ A ] N) free-·₂ : ∀ {xfree-·₁ L: M}∀ →{x xL ∈ M} → x ∈ (L → ·x ∈ (L · M) free-if₁free-·₂ : ∀ {x L M N} → x L M} ∈→ Lx →∈ xM ∈→ (ifx ∈ (L then· M else N) free-if₂free-if₁ : ∀ {x L :M ∀N} {x→ Lx M∈ N}L → x ∈ M → x ∈ (if L then M L then M else N) free-if₃free-if₂ : ∀ {x L :M ∀N} {x→ Lx M∈ N}M → x ∈ N → x ∈ (if L then M L then M else N) + free-if₃ : ∀ {x L M N} → x ∈ N → x ∈ (if L then M else N) @@ -2262,131 +2275,131 @@ A term in which no variables appear free is said to be _closed_.-_∉_ : Id → Term → Set -x ∉ M = ¬ (x ∈ M) - -closed : Term →: Id → Term → Set closed M = ∀ {x} → x ∉ M = ¬ (x ∈ M) + +closed : Term → Set +closed M = ∀ {x} → x ∉ M @@ -2396,240 +2409,240 @@ Here are proofs corresponding to the first two examples above.-f≢x : f ≢ x f≢x () example-free₁ : x ∈ (λ[ f ∶ (𝔹 ⇒ 𝔹) ] ` f · ` x) -example-free₁ = free-λ f≢x (free-·₂ free-`) - -example-free₂ : x ∈ (λ[ f ∉∶ (𝔹 ⇒ 𝔹) ] ` f · ` x) +example-free₁ (λ[= ffree-λ ∶ (𝔹 ⇒f≢x 𝔹) ] ` f(free-·₂ · ` xfree-`) + example-free₂ (free-λ: f ∉ f≢f(λ[ _)f =∶ f≢f(𝔹 ⇒ 𝔹) ] ` f · ` x) +example-free₂ (free-λ f≢f _) = f≢f refl @@ -2641,367 +2654,367 @@ Prove formally the remaining examples given above.-postulate example-free₃ : x ∈ ((λ[ f ∶ (𝔹 ⇒ 𝔹) ] ` f · ` x) · ` f) - example-free₄ : f ∈ ((λ[ f ∶ (𝔹] ⇒` 𝔹)f · ]` ` f · ` x) · ` f) example-free₅example-free₄ : xf ∉∈ (((λ[ f ∶ (𝔹 f⇒ ∶ (𝔹) ] ⇒` 𝔹) ] λ[ x ∶ 𝔹 ] ` f · ` x) · ` f) example-free₆example-free₅ : fx ∉ (λ[ f ∶ (𝔹 (λ[ f ∶ (𝔹 ⇒ 𝔹) ] λ[ x ∶ 𝔹 ] λ[ x ∶ 𝔹 ] ` f · ` x) + example-free₆ : f ∉ (λ[ f ∶ (𝔹 ⇒ 𝔹) ] λ[ x ∶ 𝔹 ] ` f · ` x) @@ -3020,115 +3033,115 @@ then `Γ` must assign a type to `x`.-free-lemma : ∀ {x M A Γ} → x ∈ M → Γ ⊢ M ∶ A → ∃ λ B → Γ x ≡ just {x M A Γ} → x ∈ M → Γ ⊢ M ∶ A → ∃ λ B → Γ x ≡ just B @@ -3164,454 +3177,454 @@ _Proof_: We show, by induction on the proof that `x` appears-free-lemma free-` (Ax Γx≡A) = (_ , Γx≡A) free-lemma (free-·₁ x∈L) (⇒-E ⊢L ⊢M) = free-lemma x∈L ⊢L -free-lemma (free-·₂ x∈M) (⇒-E ⊢L ⊢M) = free-lemma x∈Mx∈L ⊢M⊢L free-lemma (free-if₁free-·₂ x∈Lx∈M) (𝔹-E⇒-E ⊢L ⊢M) ⊢L ⊢M ⊢N) = free-lemma x∈Lx∈M ⊢L⊢M free-lemma (free-if₁ x∈L) (free-if₂𝔹-E x∈M)⊢L (𝔹-E⊢M ⊢N) ⊢L ⊢M ⊢N) = free-lemma x∈Mx∈L ⊢M⊢L free-lemma (free-if₂ x∈M) (free-if₃𝔹-E x∈N)⊢L (𝔹-E⊢M ⊢N) ⊢L ⊢M ⊢N) = free-lemma x∈Nx∈M ⊢N⊢M free-lemma (free-if₃ x∈N) (free-λ𝔹-E {x}⊢L {y}⊢M y≢x⊢N) x∈N)= (⇒-I ⊢N) with free-lemma x∈N ⊢N ...free-lemma (free-λ {x|} Γx≡C with {y} ≟y≢x x -...x∈N) (⇒-I ⊢N|) yeswith y≡xfree-lemma =x∈N ⊥-elim (y≢x y≡x)⊢N ... | no _Γx≡C with = y ≟ x +... | yes y≡x = ⊥-elim (y≢x y≡x) +... | no _ = Γx≡C @@ -3629,68 +3642,68 @@ typed in the empty context is closed (has no free variables).-postulate ∅⊢-closed : ∀ {M A} → ∅ ⊢ M ∶ A → closed M @@ -3699,294 +3712,179 @@ typed in the empty context is closed (has no free variables).-contradiction∅⊢-closed′ : ∀ {X : Set} → ∀ {x : X} → ¬ (_≡_ {A = Maybe X} (justM xA)} nothing) -contradiction→ ()∅ ⊢ M ∶ A → closed M - ∅⊢-closed′ {M} : {A∀} {M⊢M A{x} →x∈M ∅ ⊢ M ∶with A → closedfree-lemma Mx∈M ⊢M ∅⊢-closed′... | {(M}B , {A} ⊢M∅x≡B) {x}= x∈Mjust≢nothing with free-lemma x∈M ⊢M -... | (Btrans ,(sym ∅x≡B) (apply-∅ ∅x≡B) = contradiction (trans (sym ∅x≡B) (apply-∅ x)) @@ -4002,144 +3900,144 @@ exchanged for the other.-context-lemma : ∀ {Γ Γ′ M A} + → (∀ {x} → x ∈ M → Γ x ≡ Γ′ ∀ {Γ Γ′ M A}x) → (∀Γ ⊢ {x}M ∶ A + → x ∈ M → Γ x ≡ Γ′ x) - → Γ ⊢ M ∶ A - → Γ′ ⊢ M ∶ A @@ -4191,600 +4089,600 @@ _Proof_: By induction on the derivation of `Γ ⊢ M ∶ A`.-context-lemma Γ~Γ′ (Ax Γx≡A) rewrite (Γ~Γ′ free-`) = Ax Γx≡A context-lemma {Γ} {Γ′} {λ[ x ∶ A ] N} Γ~Γ′ (⇒-I ⊢N) = ⇒-I (context-lemma Γx~Γ′x A ] N} Γ~Γ′ (⇒-I ⊢N) + where + Γx~Γ′x =: ⇒-I∀ {y} → y ∈ N → (context-lemmaΓ Γx~Γ′x ⊢N) - where - Γx~Γ′x : ∀ {y} → y ∈ N → (Γ , x ∶ A) y ≡ (Γ′ , x ∶ A) y + Γx~Γ′x {y} y∈N with x ≟ y + ... (Γ′| ,yes xrefl ∶ A)= yrefl Γx~Γ′x... {y}| y∈N withno x≢y = xΓ~Γ′ ≟(free-λ yx≢y y∈N) - ... | yes refl = refl - ...context-lemma | noΓ~Γ′ x≢y (⇒-E = ⊢L Γ~Γ′ (free-λ x≢y y∈N) -context-lemma Γ~Γ′ (⇒-E ⊢L ⊢M) = ⇒-E (context-lemma (Γ~Γ′ ∘ free-·₁) ⊢L) (context-lemma (Γ~Γ′ ∘ free-·₂) ⊢M) context-lemma Γ~Γ′ 𝔹-I₁ = 𝔹-I₁ context-lemma Γ~Γ′ 𝔹-I₂ = 𝔹-I₂ context-lemma Γ~Γ′ (𝔹-E ⊢L ⊢M ⊢N) = 𝔹-E (context-lemma (Γ~Γ′ ∘ Γ~Γ′ (𝔹-Efree-if₁) ⊢L ⊢M ⊢N) = 𝔹-E (context-lemma (Γ~Γ′ ∘ free-if₁) ⊢L) (context-lemma (Γ~Γ′ ∘ free-if₂) ⊢M) (context-lemma (Γ~Γ′ ∘ free-if₃) ⊢N) @@ -4809,162 +4707,162 @@ _Lemma_: If `Γ , x ∶ A ⊢ N ∶ B` and `∅ ⊢ V ∶ A`, then-preservation-[:=] : ∀ {Γ x A N B V} + → (Γ , x ∶ A) :⊢ ∀N {Γ∶ x A N B V} → (Γ , x ∶ A) ⊢ N ∶ B - → ∅ ⊢ V ∶ A → Γ ⊢ (N [ x := V ]) ∶ B @@ -5038,478 +4936,460 @@ we show that if `∅ ⊢ V ∶ A` then `Γ ⊢ N [ x := V ] ∶ B`. We need a couple of lemmas. A closed term can be weakened to any context, and `just` is injective.-weaken-closed : ∀ {V A Γ} → ∅ ⊢ V ∶ A → Γ ⊢ V ∶ A weaken-closed {V} {A} {Γ} ⊢V = context-lemma Γ~Γ′ ⊢V + where + Γ~Γ′ : ∀ {x} → =x context-lemma∈ V → ∅ x ≡ Γ Γ~Γ′ ⊢V - where - Γ~Γ′ : ∀ {x + Γ~Γ′ {x} x∈V = ⊥-elim (x∉V → x ∈ V → ∅ x ≡ Γ xx∈V) - Γ~Γ′where + x∉V : ¬ {x} x∈V = ⊥-elim (x∉V x∈V) - where - x∉V : ¬ (x ∈ V) x∉V = ∅⊢-closed ⊢V {x} - -just-injective : ∀ {X : Set} {x y : X} → _≡_ {A = Maybe X} (just x) (just y) → x ≡ y -just-injective refl = refl-preservation-[:=] {Γ} {x} {A} (Ax {Γ,x∶A} {x′} {B} [Γ,x∶A]x′≡B) ⊢V with x ≟ x′ +...| yes x≡x′ rewrite just-injective [Γ,x∶A]x′≡B = weaken-closed ⊢V +...| no x≢x′ = Ax [Γ,x∶A]x′≡B +preservation-[:=] {Γ} {x}{BA} [Γ,x∶A]x′≡B){λ[ ⊢Vx′ with∶ xA′ ] N′} {.A′ ≟⇒ x′ -...|B′} {V} yes(⇒-I x≡x′⊢N′) rewrite just-injective [Γ,x∶A]x′≡B = weaken-closed ⊢V with x ≟ x′ ...| no x≢x′ yes x≡x′ rewrite x≡x′ = Ax [Γ,x∶A]x′≡Bcontext-lemma Γ′~Γ (⇒-I ⊢N′) -preservation-[:=]where + Γ′~Γ : ∀ {y} → y ∈ (λ[ {Γ}x′ {x}∶ A′ {A}] N′{λ[) → x′(Γ ∶, A′x′ ]∶ N′}A) {.A′y ≡ Γ ⇒y + Γ′~Γ B′} {Vy} (⇒-Ifree-λ ⊢N′x′≢y y∈N′) ⊢V with x ≟ with x′ -...| yes≟ y + ...| x≡x′yes rewrite x≡x′ x′≡y = context-lemma⊥-elim Γ′~Γ (⇒-Ix′≢y ⊢N′x′≡y) where...| no _ = refl - Γ′~Γ...| : ∀ {y} → yno x≢x′ ∈= (λ[⇒-I x′ ∶⊢N′V + where + x′x⊢N′ A′ ] N′) → (Γ , x′: ∶Γ A), yx′ ≡∶ ΓA′ y - Γ′~Γ, x ∶ A {y}⊢ (free-λN′ x′≢y∶ y∈N′) with x′ ≟ yB′ ...|x′x⊢N′ rewrite update-permute yesΓ x x′≡yA x′ = A′ ⊥-elimx≢x′ = (x′≢y x′≡y)⊢N′ ...|⊢N′V no _ =: refl(Γ , x′ ∶ A′) ⊢ N′ [ x -...| := V no x≢x′] =∶ ⇒-I B′ + ⊢N′V - where - = preservation-[:=] x′x⊢N′ : Γ , x′ ∶ A′ , x ∶ A ⊢ N′ ∶ B′⊢V - x′x⊢N′preservation-[:=] rewrite(⇒-E update-permute⊢L Γ⊢M) x⊢V = ⇒-E (preservation-[:=] ⊢L A⊢V) x′(preservation-[:=] A′ x≢x′ = ⊢N′ - ⊢N′V⊢M : ⊢V(Γ , x′ ∶ A′) +preservation-[:=] ⊢𝔹-I₁ N′ [ x := V⊢V ]= ∶ B′𝔹-I₁ +preservation-[:=] 𝔹-I₂ ⊢V = 𝔹-I₂ +preservation-[:=] (𝔹-E ⊢L ⊢M ⊢N) ⊢V = ⊢N′V𝔹-E = preservation-[:=] x′x⊢N′ ⊢V -preservation-[:=] (⇒-Epreservation-[:=] ⊢L ⊢M) ⊢V) = ⇒-E (preservation-[:=] ⊢L ⊢V) (preservation-[:=] ⊢M ⊢V) -preservation-[:=] 𝔹-I₁(preservation-[:=] ⊢N ⊢V = 𝔹-I₁ -preservation-[:=] 𝔹-I₂ ⊢V = 𝔹-I₂ -preservation-[:=] (𝔹-E ⊢L ⊢M ⊢N) ⊢V = - 𝔹-E (preservation-[:=] ⊢L ⊢V) (preservation-[:=] ⊢M ⊢V) (preservation-[:=] ⊢N ⊢V) @@ -6410,95 +6173,95 @@ reduction preserves types.-preservation : ∀ {M N A} → ∅ ⊢ M ∶ A → M ⟹ N → ∅ ⊢ N ∶ A @@ -6536,435 +6299,435 @@ _Proof_: By induction on the derivation of `∅ ⊢ M ∶ A`.-preservation (Ax Γx≡A) () +preservation (⇒-I ⊢N) () +preservation (⇒-E (⇒-I ⊢N) ⊢V) (βλ· valueV) = preservation-[:=] ⊢N ⊢V +preservation (⇒-E ⊢L ⊢M) (ξ·₁ L⟹L′) with preservation ⊢L Γx≡A) ()L⟹L′ preservation...| (⇒-I⊢L′ ⊢N)= () -preservation (⇒-E ⊢L′ ⊢M +preservation (⇒-E ⊢L ⊢M) (⇒-Iξ·₂ ⊢N)valueL ⊢VM⟹M′) (βλ· valueV)with =preservation preservation-[:=]⊢M ⊢NM⟹M′ +...| ⊢V -preservation⊢M′ (⇒-E ⊢L ⊢M) (ξ·₁ L⟹L′) with preservation ⊢L L⟹L′ -...| ⊢L′ = ⇒-E ⊢L′⊢L ⊢M⊢M′ preservation 𝔹-I₁ () +preservation 𝔹-I₂ () +preservation (𝔹-E 𝔹-I₁ ⊢M ⊢N) βif-true = (⇒-E ⊢L ⊢M) (ξ·₂ valueL M⟹M′) with preservation ⊢M M⟹M′ ...|preservation (𝔹-E 𝔹-I₂ ⊢M ⊢N) βif-false = ⊢N +preservation ⊢M′(𝔹-E = ⇒-E ⊢L ⊢M′ -preservation 𝔹-I₁ () -preservation 𝔹-I₂ () -preservation (𝔹-E 𝔹-I₁ ⊢M ⊢N) βif-true = ⊢M -preservation (𝔹-E 𝔹-I₂ ⊢M ⊢N) βif-false = ⊢N -preservation (𝔹-E ⊢L ⊢M ⊢N) (ξif L⟹L′) with preservation ⊢L L⟹L′ ...| ⊢L′ = 𝔹-E ⊢L′ ⊢M ⊢N @@ -6988,226 +6751,226 @@ term can _never_ reach a stuck state.-Normal : Term → Set Normal M = ∀ {N} → ¬ (M ⟹ N) Stuck : Term → Set Stuck M = Normal M × ¬ Value M postulate Soundness : ∀ {M N A} → ∅ ⊢ M ∶ A → M ⟹* N → ¬ (Stuck N) @@ -7216,342 +6979,342 @@ term can _never_ reach a stuck state.-Soundness′ : ∀ {M N A} → ∅ ⊢ M ∶ A → M ⟹* N → ¬ (Stuck N) Soundness′ ⊢M (M ∎) (¬M⟹N , ¬ValueM) with progress ⊢M +... | steps M⟹N = ¬M⟹N M⟹N +... | done ValueM = ¬ValueM ValueM +Soundness′ {L} {N} {A} ⊢L (_⟹⟨_⟩_ .L {M} {.N} L⟹M M⟹*N) = Soundness′ ,⊢M ¬ValueM) withM⟹*N + where + ⊢M progress: ∅ ⊢M⊢ M ∶ A -...⊢M | steps= M⟹N = ¬M⟹N M⟹N -... | done ValueM = ¬ValueM ValueM -Soundness′ {L} {N} {A} ⊢L (_⟹⟨_⟩_ .L {M} {.N} L⟹M M⟹*N) = Soundness′ ⊢M M⟹*N - where - ⊢M : ∅ ⊢ M ∶ A - ⊢M = preservation ⊢L L⟹M @@ -7731,65 +7494,65 @@ booleans, for brevity).-data Type′ : Set where _⇒_ : Type′ → Type′ → Type′ ℕ : Type′ @@ -7800,226 +7563,226 @@ plus, minus, and testing for zero.-data Term′ : Set where + `_ : Id → Term′ + λ[_∶_]_ : Id → Type′ → Term′ → Term′ + _·_ : Term′ → Term′ → Term′ + #_ : Data.Nat.ℕ → Term′ + _+_ : Term′ → Term′ → Term′ + _-_ : SetTerm′ where - `_ : Id → Term′ → Term′ Term′ λ[_∶_]_ : Id → Type′ → Term′ → Term′ - _·_ : Term′ → Term′ → Term′ - #_ : Data.Nat.ℕ → Term′ - _+_ : Term′ → Term′ → Term′ - _-_ : Term′ → Term′ → Term′ - if0_then_else_ : Term′ → Term′ → Term′ → Term′ diff --git a/src/Maps.lagda b/src/Maps.lagda index 34194ebf..723c16da 100644 --- a/src/Maps.lagda +++ b/src/Maps.lagda @@ -373,3 +373,13 @@ We now lift all of the basic lemmas about total maps to partial maps. → x ≢ y → (ρ , x ↦ v , y ↦ w) ≡ (ρ , y ↦ w , x ↦ v) update-permute ρ x v y w x≢y = TotalMap.update-permute ρ x (just v) y (just w) x≢y \end{code} + +We will also need the following basic facts about the `Maybe` type. + +\begin{code} + just≢nothing : ∀ {X : Set} → ∀ {x : X} → ¬ (_≡_ {A = Maybe X} (just x) nothing) + just≢nothing () + + just-injective : ∀ {X : Set} {x y : X} → _≡_ {A = Maybe X} (just x) (just y) → x ≡ y + just-injective refl = refl +\end{code} diff --git a/src/Stlc.lagda b/src/Stlc.lagda index c3791aef..5ddcdb91 100644 --- a/src/Stlc.lagda +++ b/src/Stlc.lagda @@ -7,7 +7,7 @@ permalink : /Stlc The _lambda-calculus_, first published by the logician Alonzo Church in 1932, is a core calculus with only three syntactic constructs: variables, abstraction, and application. It embodies the concept of -_functional abstraction_, which shows up in almsot every programming +_functional abstraction_, which shows up in almost every programming language in some form (as functions, procedures, or methods). The _simply-typed lambda calculus_ (or STLC) is a variant of the lambda calculus published by Church in 1940. It has just the three @@ -38,10 +38,10 @@ lists, records, subtyping, and mutable state. \begin{code} open import Maps using (Id; id; _≟_; PartialMap; module PartialMap) -open PartialMap using (∅) renaming (_,_↦_ to _,_∶_) +open PartialMap using (∅; just-injective) renaming (_,_↦_ to _,_∶_) open import Data.Nat using (ℕ) open import Data.Maybe using (Maybe; just; nothing) -open import Relation.Nullary using (Dec; yes; no) +open import Relation.Nullary using (Dec; yes; no; ¬_) open import Relation.Binary.PropositionalEquality using (_≡_; _≢_; refl) \end{code} @@ -86,7 +86,7 @@ and three are for the base type, booleans: Abstraction is also called lambda abstraction, and is the construct from which the calculus takes its name. -With the exception of variables, each construct either constructs +With the exception of variables, each term form either constructs a value of a given type (abstractions yield functions, true and false yield booleans) or deconstructs it (applications use functions, conditionals use booleans). We will see this again when we come @@ -177,21 +177,12 @@ two = λ[ f ∶ 𝔹 ⇒ 𝔹 ] λ[ x ∶ 𝔹 ] ` f · (` f · ` x) In an abstraction `λ[ x ∶ A ] N` we call `x` the _bound_ variable and `N` the _body_ of the abstraction. One of the most important aspects of lambda calculus is that names of bound variables are -irrelevant. Thus the two terms +irrelevant. Thus the four terms - λ[ f ∶ 𝔹 ⇒ 𝔹 ] λ[ x ∶ 𝔹 ] ` f · (` f · ` x) - -and - - λ[ g ∶ 𝔹 ⇒ 𝔹 ] λ[ y ∶ 𝔹 ] ` g · (` g · ` y) - -and - - λ[ fred ∶ 𝔹 ⇒ 𝔹 ] λ[ xander ∶ 𝔹 ] ` fred · (` fred · ` xander) - -and even - - λ[ x ∶ 𝔹 ⇒ 𝔹 ] λ[ f ∶ 𝔹 ] ` x · (` x · ` f) +* `` λ[ f ∶ 𝔹 ⇒ 𝔹 ] λ[ x ∶ 𝔹 ] ` f · (` f · ` x) `` +* `` λ[ g ∶ 𝔹 ⇒ 𝔹 ] λ[ y ∶ 𝔹 ] ` g · (` g · ` y) `` +* `` λ[ fred ∶ 𝔹 ⇒ 𝔹 ] λ[ xander ∶ 𝔹 ] ` fred · (` fred · ` xander) `` +* `` λ[ x ∶ 𝔹 ⇒ 𝔹 ] λ[ f ∶ 𝔹 ] ` x · (` x · ` f) `` are all considered equivalent. This equivalence relation is sometimes called _alpha renaming_. @@ -460,8 +451,8 @@ conditional, we first reduce the condition until it becomes a value; if the condition is true the conditional reduces to the first branch and if false it reduces to the second branch.a -In an informal presentation of the formal semantics, the rules -are written as follows. +In an informal presentation of the formal semantics, +the rules for reduction are written as follows. L ⟹ L′ --------------- ξ·₁ @@ -501,6 +492,8 @@ a deconstructor, in our case `λ` and `·`, or We give them names starting with the Greek letter beta, `β`, and indeed such rules are traditionally called beta rules. +Here are the above rules formalised in Agda. + \begin{code} infix 10 _⟹_ @@ -659,20 +652,62 @@ In general, we use typing _judgements_ of the form Γ ⊢ M ∶ A which asserts in type environment `Γ` that term `M` has type `A`. -Here `Γ` provides types for all the free variables in `M`. +Environment `Γ` provides types for all the free variables in `M`. Here are three examples. +* `` ∅ , f ∶ 𝔹 ⇒ 𝔹 , x ∶ 𝔹 ⊢ ` f · (` f · ` x) ∶ 𝔹 `` +* `` ∅ , f ∶ 𝔹 ⇒ 𝔹 ⊢ (λ[ x ∶ 𝔹 ] ` f · (` f · ` x)) ∶ 𝔹 ⇒ 𝔹 `` * `` ∅ ⊢ (λ[ f ∶ 𝔹 ⇒ 𝔹 ] λ[ x ∶ 𝔹 ] ` f · (` f · ` x)) ∶ (𝔹 ⇒ 𝔹) ⇒ 𝔹 ⇒ 𝔹 `` -* `` ∅ , f ∶ 𝔹 ⇒ 𝔹 ⊢ (λ[ x ∶ 𝔹 ] ` f · (` f · ` x)) ∶ 𝔹 ⇒ 𝔹 `` - -* `` ∅ , f ∶ 𝔹 ⇒ 𝔹 , x ∶ 𝔹 ⊢ ` f · (` f · ` x) ∶ 𝔹 `` - -Environments are maps from free variables to types, built using `∅` +Environments are partial maps from identifiers to types, built using `∅` for the empty map, and `Γ , x ∶ A` for the map that extends environment `Γ` by mapping variable `x` to type `A`. +In an informal presentation of the formal semantics, +the rules for typing are written as follows. + + Γ x ≡ A + ----------- Ax + Γ ⊢ ` x ∶ A + + Γ , x ∶ A ⊢ N ∶ B + ------------------------ ⇒-I + Γ ⊢ λ[ x ∶ A ] N ∶ A ⇒ B + + Γ ⊢ L ∶ A ⇒ B + Γ ⊢ M ∶ A + -------------- ⇒-E + Γ ⊢ L · M ∶ B + + ------------- 𝔹-I₁ + Γ ⊢ true ∶ 𝔹 + + -------------- 𝔹-I₂ + Γ ⊢ false ∶ 𝔹 + + Γ ⊢ L : 𝔹 + Γ ⊢ M ∶ A + Γ ⊢ N ∶ A + -------------------------- 𝔹-E + Γ ⊢ if L then M else N ∶ A + +As we will show later, the rules are deterministic, in that +at most one rule applies to every term. + +The proof rules come in pairs, with rules to introduce and to +eliminate each connective, labeled `-I` and `-E`, respectively. As we +read the rules from top to bottom, introduction and elimination rules +do what they say on the tin: the first _introduces_ a formula for the +connective, which appears in the conclusion but not in the premises; +while the second _eliminates_ a formula for the connective, which appears in +a premise but not in the conclusion. An introduction rule describes +how to construct a value of the type (abstractions yield functions, +true and false yield booleans), while an elimination rule describes +how to deconstruct a value of the given type (applications use +functions, conditionals use booleans). + +Here are the above rules formalised in Agda. \begin{code} Context : Set @@ -702,7 +737,38 @@ data _⊢_∶_ : Context → Term → Type → Set where Γ ⊢ if L then M else N ∶ A \end{code} -## Example type derivations +#### Example type derivations + +Here are a couple of typing examples. First, here is how +they would be written in an informal description of the +formal semantics. + +Derivation of `not`: + + ------------ Ax ------------- 𝔹-I₂ ------------- 𝔹-I₁ + Γ₀ ⊢ ` x ∶ 𝔹 Γ₀ ⊢ false ∶ 𝔹 Γ₀ ⊢ true ∶ 𝔹 + ------------------------------------------------------ 𝔹-E + Γ₀ ⊢ if ` x then false else true ∶ 𝔹 + --------------------------------------------------- ⇒-I + ∅ ⊢ λ[ x ∶ 𝔹 ] if ` x then false else true ∶ 𝔹 ⇒ 𝔹 + +where `Γ₀ = ∅ , x ∶ 𝔹`. + +Derivation of `two`: + ----------------- Ax ------------ Ax + Γ₂ ⊢ ` f ∶ 𝔹 ⇒ 𝔹 Γ₂ ⊢ ` x ∶ 𝔹 + ----------------- Ax ------------------------------------- ⇒-E + Γ₂ ⊢ ` f ∶ 𝔹 ⇒ 𝔹 Γ₂ ⊢ ` f · ` x ∶ 𝔹 + ------------------------------------------- ⇒-E + Γ₂ ⊢ ` f · (` f · ` x) ∶ 𝔹 + ------------------------------------------ ⇒-I + Γ₁ ⊢ λ[ x ∶ 𝔹 ] ` f · (` f · ` x) ∶ 𝔹 ⇒ 𝔹 + ---------------------------------------------------------- ⇒-I + ∅ ⊢ λ[ f ∶ 𝔹 ⇒ 𝔹 ] λ[ x ∶ 𝔹 ] ` f · (` f · ` x) ∶ 𝔹 ⇒ 𝔹 + +where `Γ₁ = ∅ , f ∶ 𝔹 ⇒ 𝔹` and `Γ₂ = ∅ , f ∶ 𝔹 ⇒ 𝔹 , x ∶ 𝔹`. + +Here are the above derivations formalised in Agda. \begin{code} typing₁ : ∅ ⊢ not ∶ 𝔹 ⇒ 𝔹 @@ -712,8 +778,10 @@ typing₂ : ∅ ⊢ two ∶ (𝔹 ⇒ 𝔹) ⇒ 𝔹 ⇒ 𝔹 typing₂ = ⇒-I (⇒-I (⇒-E (Ax refl) (⇒-E (Ax refl) (Ax refl)))) \end{code} +## Interaction with Agda + Construction of a type derivation is best done interactively. -We start with the declaration: +Start with the declaration: typing₁ : ∅ ⊢ not ∶ 𝔹 ⇒ 𝔹 typing₁ = ? @@ -747,4 +815,37 @@ hole. After filling in all holes, the term is as above. The entire process can be automated using Agsy, invoked with C-c C-a. +#### Non-examples + +We can also show that terms are _not_ typeable. +For example, here is a formal proof that it is not possible +to type the term `` λ[ x ∶ 𝔹 ] λ[ y ∶ 𝔹 ] ` x · ` y ``. +In other words, no type `A` is the type of this term. + +\begin{code} +contradiction : ∀ {A B} → ¬ (𝔹 ≡ A ⇒ B) +contradiction () + +notyping : ∀ {A} → ¬ (∅ ⊢ λ[ x ∶ 𝔹 ] λ[ y ∶ 𝔹 ] ` x · ` y ∶ A) +notyping (⇒-I (⇒-I (⇒-E (Ax Γx) (Ax Γy)))) = contradiction (just-injective Γx) +\end{code} + +#### Quiz + +For each of the following, given a type `A` for which it is derivable, +or explain why there is no such `A`. + +1. `` ∅ , y ∶ A ⊢ λ[ x ∶ 𝔹 ] ` x ∶ 𝔹 ⇒ 𝔹 `` +2. `` ∅ ⊢ λ[ y ∶ 𝔹 ⇒ 𝔹 ] λ[ x ∶ 𝔹 ] ` y · ` x ∶ A `` +3. `` ∅ ⊢ λ[ y ∶ 𝔹 ⇒ 𝔹 ] λ[ x ∶ 𝔹 ] ` x · ` y ∶ A `` +4. `` ∅ , x ∶ A ⊢ λ[ y : 𝔹 ⇒ 𝔹 ] `y · `x : A `` + +For each of the following, give type `A`, `B`, and `C` for which it is derivable, +or explain why there are no such types. + +1. `` ∅ ⊢ λ[ y ∶ 𝔹 ⇒ 𝔹 ⇒ 𝔹 ] λ[ x ∶ 𝔹 ] ` y · ` x ∶ A `` +2. `` ∅ , x ∶ A ⊢ x · x ∶ B `` +3. `` ∅ , x ∶ A , y ∶ B ⊢ λ[ z ∶ C ] ` x · (` y · ` z) ∶ D `` + + diff --git a/src/StlcProp.lagda b/src/StlcProp.lagda index fc98c84f..95759047 100644 --- a/src/StlcProp.lagda +++ b/src/StlcProp.lagda @@ -19,7 +19,8 @@ open import Data.Sum using (_⊎_; inj₁; inj₂) open import Relation.Nullary using (¬_; Dec; yes; no) open import Relation.Binary.PropositionalEquality using (_≡_; _≢_; refl; trans; sym) open import Maps using (Id; _≟_; PartialMap) -open Maps.PartialMap using (∅; apply-∅; update-permute) renaming (_,_↦_ to _,_∶_) +open Maps.PartialMap using (∅; apply-∅; update-permute; just≢nothing; just-injective) + renaming (_,_↦_ to _,_∶_) open import Stlc import Data.Nat using (ℕ) \end{code} @@ -320,12 +321,9 @@ postulate\begin{code} -contradiction : ∀ {X : Set} → ∀ {x : X} → ¬ (_≡_ {A = Maybe X} (just x) nothing) -contradiction () - ∅⊢-closed′ : ∀ {M A} → ∅ ⊢ M ∶ A → closed M ∅⊢-closed′ {M} {A} ⊢M {x} x∈M with free-lemma x∈M ⊢M -... | (B , ∅x≡B) = contradiction (trans (sym ∅x≡B) (apply-∅ x)) +... | (B , ∅x≡B) = just≢nothing (trans (sym ∅x≡B) (apply-∅ x)) \end{code}@@ -504,8 +502,6 @@ weaken-closed {V} {A} {Γ} ⊢V = context-lemma Γ~Γ′ ⊢V x∉V : ¬ (x ∈ V) x∉V = ∅⊢-closed ⊢V {x} -just-injective : ∀ {X : Set} {x y : X} → _≡_ {A = Maybe X} (just x) (just y) → x ≡ y -just-injective refl = refl \end{code} \begin{code}