Renaming
A tool stocked ahead of need: nothing in the trunk consumes it yet, and its first consumers arrive with Part 4's deeper chapters. First, variables.
The syntax chapter pointed out an absence: no substitution, no weakening. The quantifier clauses take bodies in an extended context directly, so the classical apparatus for moving variables around never has to exist. What little variable motion the book does need is covered by one device: renaming, a map ρ : Fin n → Fin m pushed through a formula, with a single correctness theorem that handles weakening, exchange, and contraction in one stroke.
{-# OPTIONS --cubical --safe --guardedness #-} module FOL.Manipulation.Renaming where open import Base.Prelude open import Base.Truth open import FOL.ZFStructure using ( ZFStructure ) open import FOL.Syntax using ( Term; con; var ; Formula; _∈̇_; _≐_; _∧̇_; _∨̇_; _⇒̇_; ¬̇_; ⊤̇; ⊥̇; ∃̇_; ∀̇_; ∀̇∈; ∃̇∈ ) import FOL.Semantics
The syntactic layer
Under a binder the renaming must step aside for the freshly bound variable: liftρ ρ keeps variable 0 fixed and shifts everything else through ρ. With that, pushing a renaming through terms and formulas is one clause per constructor; note it moves only variables, leaving constants alone, exactly complementary to the mapFo of the previous chapter.
liftρ : ∀ {n m} → (Fin n → Fin m) → Fin (suc n) → Fin (suc m) liftρ ρ zero = zero liftρ ρ (suc i) = suc (ρ i) renameTm : ∀ {ℓc} {K : Type ℓc} {n m} → (Fin n → Fin m) → Term K n → Term K m renameTm ρ (con k) = con k renameTm ρ (var i) = var (ρ i) renameFo : ∀ {ℓc} {K : Type ℓc} {n m} → (Fin n → Fin m) → Formula K n → Formula K m renameFo ρ (t ∈̇ u) = renameTm ρ t ∈̇ renameTm ρ u renameFo ρ (t ≐ u) = renameTm ρ t ≐ renameTm ρ u renameFo ρ (φ ∧̇ ψ) = renameFo ρ φ ∧̇ renameFo ρ ψ renameFo ρ (φ ∨̇ ψ) = renameFo ρ φ ∨̇ renameFo ρ ψ renameFo ρ (φ ⇒̇ ψ) = renameFo ρ φ ⇒̇ renameFo ρ ψ renameFo ρ (¬̇ φ) = ¬̇ renameFo ρ φ renameFo ρ ⊤̇ = ⊤̇ renameFo ρ ⊥̇ = ⊥̇ renameFo ρ (∃̇ φ) = ∃̇ renameFo (liftρ ρ) φ renameFo ρ (∀̇ φ) = ∀̇ renameFo (liftρ ρ) φ renameFo ρ (∀̇∈ t φ) = ∀̇∈ (renameTm ρ t) (renameFo (liftρ ρ) φ) renameFo ρ (∃̇∈ t φ) = ∃̇∈ (renameTm ρ t) (renameFo (liftρ ρ) φ)
The semantic layer
When does renaming preserve meaning? Precisely when the two environments say the same things to corresponding variables: Agrees ρ γ δ asks that looking up ρ i in the big environment equals looking up i in the small one, and
agrees∷ shows the condition survives pushing one new value onto both sides, which is what happens under a binder. The development is generic over the truth algebra, the structure, and the constant interpretation.
module Sat {ℓ ℓ'} (𝕋 : TruthAlgebra ℓ ℓ') (𝒮 : ZFStructure 𝕋) {ℓc} {K : Type ℓc} (ι : K → ZFStructure.S 𝒮) where open TruthAlgebra 𝕋 open ZFStructure 𝒮 private module Sem = FOL.Semantics 𝕋 𝒮 open Sem using ( _^_ ) open Sem.At K ι using ( _⊨_; ⟦_⟧ ) Agrees : ∀ {n m} → (Fin n → Fin m) → S ^ m → S ^ n → Type ℓ Agrees ρ γ δ = ∀ i → lookup (ρ i) γ ≡ lookup i δ
The correctness theorem: a renamed formula in the big environment means the same as the original in the small one. Terms first, then the usual induction, every case a congruence, the binder cases stepping through agrees∷. Weakening (inserting an unused variable), exchange, and contraction are all instances, obtained by choosing ρ.
agrees∷ : ∀ {n m} {ρ : Fin n → Fin m} {γ : S ^ m} {δ : S ^ n} (x : S) → Agrees ρ γ δ → Agrees (liftρ ρ) (x ∷ γ) (x ∷ δ) agrees∷ x ag zero = refl agrees∷ x ag (suc i) = ag i ⟦⟧-rename : ∀ {n m} (ρ : Fin n → Fin m) (t : Term K n) (γ : S ^ m) (δ : S ^ n) → Agrees ρ γ δ → ⟦ renameTm ρ t ⟧ γ ≡ ⟦ t ⟧ δ ⟦⟧-rename ρ (con k) γ δ ag = refl ⟦⟧-rename ρ (var i) γ δ ag = ag i ⊨-rename : ∀ {n m} (ρ : Fin n → Fin m) (φ : Formula K n) (γ : S ^ m) (δ : S ^ n) → Agrees ρ γ δ → (γ ⊨ renameFo ρ φ) ≡ (δ ⊨ φ) ⊨-rename ρ (t ∈̇ u) γ δ ag = cong₂ _∈ˢ_ (⟦⟧-rename ρ t γ δ ag) (⟦⟧-rename ρ u γ δ ag) ⊨-rename ρ (t ≐ u) γ δ ag = cong₂ _≈ˢ_ (⟦⟧-rename ρ t γ δ ag) (⟦⟧-rename ρ u γ δ ag) ⊨-rename ρ (φ ∧̇ ψ) γ δ ag = cong₂ _⊓_ (⊨-rename ρ φ γ δ ag) (⊨-rename ρ ψ γ δ ag) ⊨-rename ρ (φ ∨̇ ψ) γ δ ag = cong₂ _⊔_ (⊨-rename ρ φ γ δ ag) (⊨-rename ρ ψ γ δ ag) ⊨-rename ρ (φ ⇒̇ ψ) γ δ ag = cong₂ _⇒_ (⊨-rename ρ φ γ δ ag) (⊨-rename ρ ψ γ δ ag) ⊨-rename ρ (¬̇ φ) γ δ ag = cong ¬_ (⊨-rename ρ φ γ δ ag) ⊨-rename ρ ⊤̇ γ δ ag = refl ⊨-rename ρ ⊥̇ γ δ ag = refl ⊨-rename ρ (∃̇ φ) γ δ ag = cong (⋁ S) (funExt (λ x → ⊨-rename (liftρ ρ) φ (x ∷ γ) (x ∷ δ) (agrees∷ x ag))) ⊨-rename ρ (∀̇ φ) γ δ ag = cong (⋀ S) (funExt (λ x → ⊨-rename (liftρ ρ) φ (x ∷ γ) (x ∷ δ) (agrees∷ x ag))) ⊨-rename ρ (∀̇∈ t φ) γ δ ag = cong (⋀ S) (funExt (λ x → cong₂ _⇒_ (cong (x ∈ˢ_) (⟦⟧-rename ρ t γ δ ag)) (⊨-rename (liftρ ρ) φ (x ∷ γ) (x ∷ δ) (agrees∷ x ag)))) ⊨-rename ρ (∃̇∈ t φ) γ δ ag = cong (⋁ S) (funExt (λ x → cong₂ _⊓_ (cong (x ∈ˢ_) (⟦⟧-rename ρ t γ δ ag)) (⊨-rename (liftρ ρ) φ (x ∷ γ) (x ∷ δ) (agrees∷ x ag))))
Recap
Renaming is the book's entire variable calculus: renameFo on syntax,
⊨-rename on meaning, with Agrees naming the exact condition under which nothing changes. The book's variable machinery now exists, once and in full, ahead of the heavy consumers waiting in Part 4.