Notes on Untyped Conversion

Untyped Conversion

Untyped conversion (and therefore reduction), I think, is meant to model the implementation of a conversion checker. (I’m really not the best person to ask.) Ideally, you’d want it to be entirely decoupled from the type checker, which is a very Software Engineering 110 reasonable thing to expect. An implementation outline might look like this:

  1. Reduce both terms sufficiently.
  2. If they look different, give up.
  3. Recur on subterms.

β€œSufficiently” might mean normal form or weak head normal form or whatever reasonable form you like. So we might formalize that as follows:

───────────────────────── Ξ²
(Ξ»x: Ο„. e) e' ⊳ e[x ↦ e']

────── ⊳*-refl
e ⊳* e

e₁ ⊳ eβ‚‚
eβ‚‚ ⊳* e₃
──────── ⊳*-trans
e₁ ⊳* e₃

eᡒ ⊳* eᡒ'
─────────────────────── ⊳*-cong
e[x ↦ eα΅’] ⊳* e[x ↦ eα΅’']

e₁ ⊳* e
eβ‚‚ ⊳* e
─────── β‰ˆ-red
e₁ β‰ˆ eβ‚‚

The β€œsufficiently” part comes from ⊳*-trans, where you take as many steps as you need. The congruence rules are the most tedious, since you need one for every syntactic form, so I’ve instead lazily written them as a single substitution. Conversion is an equivalence relation, as you’d expect: it’s reflexive (by ⊳*-refl), it’s symmetric (by swapping premises in β‰ˆ-red), it’s substitutive (by ⊳*-cong), and it’s transitive if reduction is confluent, because then you can construct the conversion by where the pairs meet. (Confluence left as an exercise for the reader.)

e₁ β‰ˆ eβ‚‚ β‰ˆ e₃
 \  /  \  /
  e₁₂   e₂₃  ← confluence gives this diamond
    \  /
     e*

e₁ ⊳* e*
e₃ ⊳* e*
────────
e₁ β‰ˆ e₃

Cumulativity + Ξ·

Dually to Ξ², let’s now add Ξ·-contraction, but suppose we had cumulativity (or more generally, any subtyping relation). Then Ξ·-contraction is no good, since it breaks confluence. Supposing we had types Οƒ ≀ Ο„, Ξ»x: Οƒ. (Ξ»y: Ο„. f y) x could either Ξ²-reduce to Ξ»x: Οƒ. f x, or Ξ·-contract with congruence to Ξ»y: Ο„. f y, but these are no longer Ξ±-equivalent due to the type annotation. Breaking confluence then means breaking transitivity of conversion as well. Ξ·-contraction then isn’t an option with Church-style type-annotated intrinsically-typed terms.

What about Ξ·-expansion? If you had a neutral term typed as a function, you may expand it once. But with untyped conversion, there’s no way to tell whether the term is indeed typed as a function, and you can’t go around Ξ·-expanding any old neutral term willy-nilly.

Ξ·-Conversion

The remaining solution is then to add Ξ·-equivalence as part of conversion. There are two ways to do this; the first is the obvious way.

────────────── β‰ˆ-Ξ·β‚— (+ β‰ˆ-Ξ·α΅£ symmetrically)
Ξ»x: Ο„. f x β‰ˆ f

This immediately requires explicit transitivity and congruence rules, since Ξ»x: Ο„. Ξ»y: Οƒ. f x y β‰ˆ f wouldn’t hold otherwise. The other way is to check that one side is a function, then apply the other side.

e₁ ⊳* Ξ»x: Ο„. e₁'
eβ‚‚ ⊳* eβ‚‚'
x βˆ‰ FV(eβ‚‚')
e₁' β‰ˆ eβ‚‚' x
──────────────── β‰ˆ-Ξ·β‚— (+ β‰ˆ-Ξ·α΅£ symmetrically)
e₁ β‰ˆ eβ‚‚

This looks more ideal since it seems like it easily extends the implementation outline:

  1. Reduce both terms sufficiently.
  2. If one of them looks like a function, recur according to β‰ˆ-Ξ·.
  3. If they look different, give up.
  4. Recur on subterms.

You then still need congruence rules for step 4; otherwise F G β‰ˆ F (Ξ»X: 𝒰. G X) would not hold given some F: (𝒰 β†’ 𝒰) β†’ 𝒰 and G: 𝒰 β†’ 𝒰. It seems like transitivity might hold without explicitly adding it as a rule, again by confluence, but this time requiring induction on derivation heights rather than structural induction, and first showing that the derivation of any symmetric conversion has the same height.

Multiple Ξ·s

Suppose we were in a setting with multiple syntactic functions, for instance the Calculus of Constructions or System F, where abstraction by and application of a type differs from ordinary term abstractions and applications.

Ξ“, x: Οƒ ⊒ e: Ο„               Ξ“, Ξ±: ⋆ ⊒ e : Ο„
───────────────────────      ─────────────────
Ξ“ ⊒ Ξ»x: Οƒ. e : Ξ x: Οƒ. Ο„      Ξ“ ⊒ Λα. e : βˆ€Ξ±. Ο„

Ξ“ ⊒ e : Ξ x: Οƒ. Ο„             Ξ“ ⊒ e : βˆ€Ξ±. Ο„
Ξ“ ⊒ e' : Οƒ                   Ξ“ ⊒ Οƒ : ⋆
────────────────────         ────────────────────
Ξ“ ⊒ e e' : Ο„[x ↦ e']         Ξ“ ⊒ e [Οƒ] : Ο„[Ξ± ↦ Οƒ]

(Ξ»x: Ο„. e) e' ⊳ e[x ↦ e']    (Λα. e) [Οƒ] ⊳ e[Ξ± ↦ Οƒ]

If both of these functions had Ξ·-conversion rules, transitivity wouldn’t hold, especially for open terms. Specifically, the conversions Ξ»x: Ο„. f x β‰ˆ f and f β‰ˆ Λα. f [Ξ±] are both derivable (despite being ill-typed when considered simultaneously, since conversion is untyped), but Ξ»x: Ο„. f x β‰ˆ Λα. f [Ξ±] is impossible to derive.

Equality Reflection + Ξ·

In Oury’s Extensional Calculus of Constructions1, equality reflection is added to untyped conversion (≑ denoting the equality type).

Ξ“ ⊒ p: x ≑ y
──────────── β‰ˆ-reflect
Ξ“ ⊒ x β‰ˆ y

There’s a clash between the fact that ill-typed terms can still be convertible, and that equality reflection only makes sense when everything is well-typed. In particular, you cannot simultaneously have congruence and transitivity of conversion, since it allows you to derive an inconsistency. Concretely, using an ill-typed proof of ⊀ ≑ βŠ₯ (where ⊀ is trivially inhabited by βˆ— and βŠ₯ is uninhabited), you can convert from ⊀ to βŠ₯.

Β· ⊒ ⊀ β‰ˆ (Ξ»p: ⊀ ≑ βŠ₯. ⊀) refl    (by Ξ²-reduction)
      β‰ˆ (Ξ»p: ⊀ ≑ βŠ₯. βŠ₯) refl    (by β‰ˆ-cong and β‰ˆ-reflect on (p: ⊀ ≑ βŠ₯) ⊒ p: ⊀ ≑ βŠ₯)
      β‰ˆ βŠ₯                      (by Ξ²-reduction)

Note the ill-typedness of the application: refl is clearly not a proof of ⊀ ≑ βŠ₯. Evidently this leads to a contradiction, since you could then convert the type of βˆ— from ⊀ to βŠ₯.

Addendum: What does Coq actually do?

Coq’s conversion algorithm can be found in its kernel, which is actually one giant algorithm parametrized over whether it should be checking convertibility or cumulativity. The below is my attempt at writing it down as rules (ignoring cases related to (co)inductives), with MetaCoq’s conversion in pCuIC as guidance. [Κ€] represents the relation over which they are parametrized, which can be either [β‰ˆ] or [≀].

i = j
────────── β‰ˆ-𝒰
𝒰ᡒ [β‰ˆ] 𝒰ⱼ

i ≀ j
────────── ≀-𝒰
𝒰ᡒ [≀] 𝒰ⱼ

τ₁ [β‰ˆ] Ο„β‚‚
σ₁ [Κ€] Οƒβ‚‚
───────────────────────── Κ€-Ξ 
Ξ x: τ₁. σ₁ [Κ€] Ξ x: Ο„β‚‚. Οƒβ‚‚

t₁ [Κ€] tβ‚‚
e₁ [β‰ˆ] eβ‚‚
─────────────── Κ€-app
t₁ e₁ [Κ€] tβ‚‚ eβ‚‚

τ₁ [β‰ˆ] Ο„β‚‚
e₁ [Κ€] eβ‚‚
───────────────────────── Κ€-Ξ»
Ξ»x: τ₁. e₁ [Κ€] Ξ»x: Ο„β‚‚. eβ‚‚

τ₁ [β‰ˆ] Ο„β‚‚
t₁ [β‰ˆ] tβ‚‚
e₁ [Κ€] eβ‚‚
───────────────────────────────────────────── Κ€-let
let x: τ₁ ≔ t₁ in e₁ [Κ€] let x: Ο„β‚‚ ≔ tβ‚‚ in eβ‚‚

e₁ [Κ€] eβ‚‚
─────────────────────── (catch-all for remaining syntactic constructs)
t[x ↦ e₁] [Κ€] t[x ↦ eβ‚‚]

eβ‚‚ x ⊳* eβ‚‚'
e₁ [β‰ˆ] eβ‚‚'
──────────────── Κ€-Ξ·β‚—
Ξ»x: Ο„. e₁ [Κ€] eβ‚‚

e₁ x ⊳* e₁'
e₁' [β‰ˆ] eβ‚‚
──────────────── Κ€-Ξ·α΅£
e₁ [Κ€] Ξ»x: Ο„. eβ‚‚

The β€œreal” conversion and subtyping rules are then the confluent closure of the above. The actual implementation performs more reduction as needed; I think this is just for performance reasons, and because there’s no way to forsee how many steps you’ll end up having to take during initial reduction.

e₁ ⊳* e₁'
eβ‚‚ ⊳* eβ‚‚'
e₁' [β‰ˆ] eβ‚‚'
───────────
e₁ β‰ˆ eβ‚‚

e₁ ⊳* e₁'
eβ‚‚ ⊳* eβ‚‚'
e₁' [≀] eβ‚‚'
───────────
e₁ ≀ eβ‚‚

Reflexivity and symmetry of conversion and reflexivity of subtyping are easy to see. Congruence is built into the rules (shown with the same substitution notation as before). Evidently conversion implies subtyping, but this time indirectly.

  1. Nicolas Oury. (TPHOLs 2005). Extensionality in the Calculus of Constructions. ᴅᴏΙͺ: 10.1007/11541868_18.Β