带有模糊终止的条款

With clauses obscuring termination

我正在尝试在 agda 中定义二进制数,但 agda 看不到 ⟦_⇑⟧ 正在终止。我真的不想打破可访问性关系。我如何向 agda 显示 n 变小了?

module Binary where

open import Data.Nat using (ℕ; _+_; +-suc)
open ℕ

2* : ℕ → ℕ
2* n = n + n

data Parity : ℕ → Set where
   : ∀ k → Parity (2* k)
   : ∀ k → Parity (1 + 2* k)

parity : ∀ n → Parity n
parity zero =  0
parity (suc n) with parity n
parity (suc .(k + k)) |  k =  k
parity (suc .(suc (k + k))) |  k rewrite sym (+-suc k k) =  (suc k)

data  : Set where
   : 
   :  → 
   :  → 

⟦_⇓⟧ :  → ℕ
⟦  ⇓⟧ = 0
⟦  b ⇓⟧ = 2* ⟦ b ⇓⟧
⟦  b ⇓⟧ = 1 + 2* ⟦ b ⇓⟧

⟦_⇑⟧ : ℕ → 
⟦ zero ⇑⟧ = 
⟦ suc n ⇑⟧ with parity n
⟦ suc .(k + k) ⇑⟧ |  k =  ⟦ k ⇑⟧
⟦ suc .(suc (k + k)) ⇑⟧ |  k =  ⟦ k ⇑⟧

错误:

Termination checking failed for the following functions:
  ⟦_⇑⟧
Problematic calls:
  ⟦ k ⇑⟧

终止检查有充分的理由失败,因为以下函数在其输入上不是结构递归的:

⟦_⇑⟧ : ℕ → 
⟦ zero ⇑⟧ = 
⟦ suc n ⇑⟧ with parity n
⟦ suc .(k + k) ⇑⟧ |  k =  ⟦ k ⇑⟧
⟦ suc .(suc (k + k)) ⇑⟧ |  k =  ⟦ k ⇑⟧

Agda 甚至会告诉您有问题的调用是什么:⟦ k ⇑⟧。 (在这种情况下,有两个这样的格式错误的调用)。

虽然我同意它可能 看起来 该函数是在结构较小的参数上调用的,但事实并非如此。要理解为什么,你必须看到 k 被用作函数调用的输入,_+_,并且只有这个函数的结果在结构上小于 n,而不是 k 本身。并且 agda 无法知道以下 属性 关于 _+_

∀ {n} → n < suc (n + n)

如果您提供此类引理的证明,您可以使用 _<_ 有充分根据的事实使您的函数在 Acc 上进行结构递归,但您似乎不愿意这样做.

理解为什么 Agda 不能 知道这终止的一个简单方法如下:想象你用 suc .(a ∸ b) 替换 suc .(k + k) 并递归调用你的函数超过 a。从 agda 的角度来看,两者是相同的情况,在这种情况下,它通常不会终止,除非 b 恰好是 0.


这是根据终止更正的模块

module Binary where

open import Data.Nat
open import Data.Nat.Properties
open import Relation.Binary.PropositionalEquality
open import Data.Product
open import Induction.Nat
open import Induction.WellFounded

2* : ℕ → ℕ
2* n = n + n

data Parity : ℕ → Set where
   : ∀ k → Parity (2* k)
   : ∀ k → Parity (1 + 2* k)

parity : ∀ n → Parity n
parity zero =  0
parity (suc n) with parity n
parity (suc .(k + k)) |  k =  k
parity (suc .(suc (k + k))) |  k rewrite sym (+-suc k k) =  (suc k)

data  : Set where
   : 
   :  → 
   :  → 

⟦_⇓⟧ :  → ℕ
⟦  ⇓⟧ = 0
⟦  b ⇓⟧ = 2* ⟦ b ⇓⟧
⟦  b ⇓⟧ = 1 + 2* ⟦ b ⇓⟧

decr : ∀ {n} → n < suc (n + n)
decr {n} = s≤s (m≤m+n n n) 

helper : (n : ℕ) → Acc _<_ n → 
helper zero a = 
helper (suc n) a with parity n
helper (suc .(k + k)) (acc rs) |  k =  (helper k (rs _ decr))
helper (suc .(suc (k + k))) (acc rs) |  k =  (helper k (rs _ (s≤s (<⇒≤ decr))))

⟦_⇑⟧ : ℕ → 
⟦ n ⇑⟧ = helper n (<-wellFounded n)

我也怀疑你定义的正确性,结果证明我是对的,例如,考虑以下定义:

test : ℕ
test = ⟦ ⟦ 124 ⇑⟧ ⇓⟧

Agda returns 2 求值时 test.

考虑定义:

test₁ : ℕ
test₁ = ⟦ ⟦ 16 ⇑⟧ ⇓⟧

Agda returns 14 计算时 test₁

为了更正您的定义,您可以从标准库中的工作中获取灵感,可以是模块 Data.Bin(已弃用)或模块 Data.Nat.Binary,具体取决于哪个版本你拥有的标准库。