Files
lean-pl-tutorials/tutorial-02-semantics/13-hm-declarative.org
Hermes Agent 6e2914b06e migrate all tutorials from Markdown to Org mode
Converted with pandoc 3.7 (markdown → org), all 17 files:
- README, references, 15 tutorial units
- Internal file links updated from .md to .org
- Source code blocks (#+begin_src lean) preserved
- Tables, math notation, links intact

For the Emacs workflow.
2026-05-28 20:15:38 +02:00

5.0 KiB
Raw Blame History

Unit 13 — Hindley-Milner Declarative Typing Rules

Tutorial 2: PL Semantics in Lean · ← Back to README

Goals

  • Extend STLC with let-polymorphism
  • Encode HM types with type schemes ∀α. τ
  • Formalize the 6 declarative typing rules (Var, App, Abs, Let, Inst, Gen)
  • Understand the distinction between monomorphic (τ) and polymorphic (σ = ∀α.τ) types

Sources

Background

HM adds let-polymorphism to STLC:

let x = e₁ in e₂

In STLC, x would have a single monomorphic type. In HM, x gets a type scheme — e.g., ∀α. αα for the identity function — and each use of x instantiates the scheme with fresh type variables.

The declarative rules:

Var:    Γ, x:σ ⊢ x : σ
App:    Γ ⊢ e₁ : τ₁ → τ₂    Γ ⊢ e₂ : τ₁   ⇛   Γ ⊢ e₁ e₂ : τ₂
Abs:    Γ, x:τ₁ ⊢ e : τ₂   ⇛   Γ ⊢ λx.e : τ₁ → τ₂
Let:    Γ ⊢ e₁ : σ       Γ, x:σ ⊢ e₂ : τ   ⇛   Γ ⊢ let x = e₁ in e₂ : τ
Inst:   Γ ⊢ e : ∀α.τ   ⇛   Γ ⊢ e : τ[α := τ']
Gen:    Γ ⊢ e : τ   ∧   α ∉ ftv(Γ)   ⇛   Γ ⊢ e : ∀α.τ

Exercises

-- 13.1 — Types and type schemes
inductive MonoType where
  | tvar  (id : Nat)              -- type variable α
  | fn    (τ₁ τ₂ : MonoType)      -- τ₁ → τ₂
deriving Repr, DecidableEq

notation:40 τ₁ " ⇒ " τ₂ => MonoType.fn τ₁ τ₂

-- A type scheme: ∀α₁...αₙ. τ  (quantified over a set of type variables)
structure TypeScheme where
  vars : List Nat               -- bound type variables
  body : MonoType
deriving Repr

-- 13.2 — HM expression syntax (extend STLC with `let`)
inductive HMExpr where
  | var (i : Nat)                -- de Bruijn index
  | lam (body : HMExpr)          -- λ. e
  | app (f a : HMExpr)           -- f a
  | lett (e₁ e₂ : HMExpr)        -- let x = e₁ in e₂
deriving Repr

-- 13.3 — Environments
-- Γ maps de Bruijn indices to type schemes
def HMEnv := List TypeScheme

-- 13.4 — Declarative typing rules
inductive HMTyping : HMEnv  HMExpr  TypeScheme  Prop where

  -- Var: look up variable in the environment
  | var (Γ : HMEnv) (i : Nat) (h : lookup Γ i = some σ) : HMTyping Γ (HMExpr.var i) σ

  -- Abs: λx. e  — note: x gets a monomorphic type in the lambda body
  | abs (Γ : HMEnv) (e : HMExpr) (τ₁ τ₂ : MonoType)
        (h : HMTyping ({vars := [], body := τ₁} :: Γ) e {vars := [], body := τ₂}) :
      HMTyping Γ (HMExpr.lam e) {vars := [], body := τ₁  τ₂}

  -- App: e₁ e₂
  | app (Γ : HMEnv) (e₁ e₂ : HMExpr) (σ τ₁ τ₂ : MonoType) (σ' : TypeScheme)
        (h₁ : HMTyping Γ e₁ σ') (h₂ : HMTyping Γ e₂ {vars := [], body := τ₁})
        (h_eq : σ' = {vars := [], body := τ₁  τ₂}) :
      HMTyping Γ (HMExpr.app e₁ e₂) {vars := [], body := τ₂}

  -- Let: e₁ is generalized and e₂ can use the polymorphic type
  | lett (Γ : HMEnv) (e₁ e₂ : HMExpr) (σ σ' : TypeScheme) (τ : MonoType)
        (h₁ : HMTyping Γ e₁ σ) (h₂ : HMTyping (σ :: Γ) e₂ σ') :
      HMTyping Γ (HMExpr.lett e₁ e₂) σ'

  -- Gen: generalize over free type variables not in the environment
  | gen (Γ : HMEnv) (e : HMExpr) (σ : TypeScheme) (αs : List Nat)
        (h : HMTyping Γ e σ) (hfresh :  α, α  αs  α  ftv_env Γ) :
      HMTyping Γ e {σ with vars := αs ++ σ.vars}

  -- Inst: instantiate a type scheme
  | inst (Γ : HMEnv) (e : HMExpr) (σ : TypeScheme) (τ : MonoType) (subst : Nat  MonoType)
        (h : HMTyping Γ e σ) (hinst : apply_subst subst σ = τ) :
      HMTyping Γ e {vars := [], body := τ}

-- 13.5 — Exercise: the identity function is polymorphic
def id_type : TypeScheme := {vars := [0], body := MonoType.tvar 0  MonoType.tvar 0}

theorem id_polymorphic : HMTyping [] (HMExpr.lam (HMExpr.var 0)) id_type :=
  by
    sorry

-- 13.6 — Exercise: let x = λy. y in x x  (instantiation of polymorphic identity)
-- This term should be well-typed — the identity is used at two different types
def self_app_id : HMExpr :=
  HMExpr.lett (HMExpr.lam (HMExpr.var 0)) (HMExpr.app (HMExpr.var 0) (HMExpr.var 0))

theorem self_app_id_typed (τ : MonoType) :
    HMTyping [] self_app_id {vars := [], body := τ  τ} :=
  by
    sorry

Previous: Unit 12 · Next: Unit 14 — Algorithm W