Skip to content

Commit 189a7b5

Browse files
hyperpolymathclaude
andcommitted
refactor(agda): remove TERMINATING pragma via mutual block split
_≡ᵛ_ used {-# TERMINATING #-} because Agda's termination checker could not see the lexicographic (type-index, list-length) measure through the TList and TRecord recursive cases. Fix: split into a mutual block — _≡ᵛ_, eqList, eqRecord. - _≡ᵛ_ {TList τ} delegates entirely to eqList (no self-recursion) - eqList terminates by structural List induction, calls _≡ᵛ_ on elements (τ < TList τ — strict subterm of type index) - eqRecord terminates by structural field-list induction, calls _≡ᵛ_ on parts (τ and TRecord fs are both strict subterms of TRecord ((f,τ)∷fs)) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 3d0af28 commit 189a7b5

1 file changed

Lines changed: 40 additions & 29 deletions

File tree

academic/formal-verification/agda/Phronesis.agda

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -155,35 +155,46 @@ open import Data.Bool using () renaming (_≟_ to _≟ᵇ_)
155155

156156
-- Decidable equality on semantic values, by induction on the type index.
157157
-- TFloat is represented as ℤ (placeholder), TDateTime as ℤ, TIP as 4-tuple of ℕ.
158-
-- TRecord and TList use structural recursion.
159-
{-# TERMINATING #-}
160-
_≡ᵛ_ : {τ} ⟦ τ ⟧ ⟦ τ ⟧ Bool
161-
_≡ᵛ_ {TInt} a b with a ≟ℤ b
162-
... | yes _ = true
163-
... | no _ = false
164-
_≡ᵛ_ {TFloat} a b with a ≟ℤ b
165-
... | yes _ = true
166-
... | no _ = false
167-
_≡ᵛ_ {TString} a b with a ≟ˢ b
168-
... | yes _ = true
169-
... | no _ = false
170-
_≡ᵛ_ {TBool} a b with a ≟ᵇ b
171-
... | yes _ = true
172-
... | no _ = false
173-
_≡ᵛ_ {TIP} (a₁ , a₂ , a₃ , a₄) (b₁ , b₂ , b₃ , b₄)
174-
with a₁ ≟ⁿ b₁ | a₂ ≟ⁿ b₂ | a₃ ≟ⁿ b₃ | a₄ ≟ⁿ b₄
175-
... | yes _ | yes _ | yes _ | yes _ = true
176-
... | _ | _ | _ | _ = false
177-
_≡ᵛ_ {TDateTime} a b with a ≟ℤ b
178-
... | yes _ = true
179-
... | no _ = false
180-
_≡ᵛ_ {TList τ} [] [] = true
181-
_≡ᵛ_ {TList τ} (x ∷ xs) (y ∷ ys) = (_≡ᵛ_ {τ} x y) ∧ (_≡ᵛ_ {TList τ} xs ys)
182-
_≡ᵛ_ {TList _} _ _ = false
183-
_≡ᵛ_ {TRecord []} tt tt = true
184-
_≡ᵛ_ {TRecord ((f , τ) ∷ fs)} (v , vs) (w , ws) =
185-
(_≡ᵛ_ {τ} v w) ∧ (_≡ᵛ_ {TRecord fs} vs ws)
186-
_≡ᵛ_ {TNull} tt tt = true
158+
-- TList and TRecord are split into helper functions in a mutual block so Agda's
159+
-- termination checker sees the structural decrease explicitly:
160+
-- * eqList decreases on the List (structural); calls _≡ᵛ_ on elements (τ < TList τ)
161+
-- * eqRecord decreases on the field List (structural); calls _≡ᵛ_ on parts (τ < TRecord)
162+
-- This replaces the former {-# TERMINATING #-} pragma.
163+
mutual
164+
_≡ᵛ_ : {τ} ⟦ τ ⟧ ⟦ τ ⟧ Bool
165+
_≡ᵛ_ {TInt} a b with a ≟ℤ b
166+
... | yes _ = true
167+
... | no _ = false
168+
_≡ᵛ_ {TFloat} a b with a ≟ℤ b
169+
... | yes _ = true
170+
... | no _ = false
171+
_≡ᵛ_ {TString} a b with a ≟ˢ b
172+
... | yes _ = true
173+
... | no _ = false
174+
_≡ᵛ_ {TBool} a b with a ≟ᵇ b
175+
... | yes _ = true
176+
... | no _ = false
177+
_≡ᵛ_ {TIP} (a₁ , a₂ , a₃ , a₄) (b₁ , b₂ , b₃ , b₄)
178+
with a₁ ≟ⁿ b₁ | a₂ ≟ⁿ b₂ | a₃ ≟ⁿ b₃ | a₄ ≟ⁿ b₄
179+
... | yes _ | yes _ | yes _ | yes _ = true
180+
... | _ | _ | _ | _ = false
181+
_≡ᵛ_ {TDateTime} a b with a ≟ℤ b
182+
... | yes _ = true
183+
... | no _ = false
184+
_≡ᵛ_ {TList τ} xs ys = eqList {τ} xs ys
185+
_≡ᵛ_ {TRecord fs} vs ws = eqRecord {fs} vs ws
186+
_≡ᵛ_ {TNull} tt tt = true
187+
188+
-- List equality: structural recursion on the List; calls _≡ᵛ_ on elements.
189+
eqList : {τ} List ⟦ τ ⟧ List ⟦ τ ⟧ Bool
190+
eqList [] [] = true
191+
eqList (x ∷ xs) (y ∷ ys) = _≡ᵛ_ x y ∧ eqList xs ys
192+
eqList _ _ = false
193+
194+
-- Record equality: structural recursion on the field List.
195+
eqRecord : {fs} ⟦ TRecord fs ⟧ ⟦ TRecord fs ⟧ Bool
196+
eqRecord {[]} tt tt = true
197+
eqRecord {(_ , τ) ∷ fs} (v , vs) (w , ws) = _≡ᵛ_ v w ∧ eqRecord {fs} vs ws
187198

188199
-- Integer less-than via the standard library ordering.
189200
_<ᵛ_ : Bool

0 commit comments

Comments
 (0)