如何在 Agda 中为 `Vec` 编写安全的 `length` 函数?

How to write a safe `length` function to a `Vec` in Agda?

因为我们有 Data.Vec,所以我们知道 Vec 是什么。

我想证明Nat和Vec ⊤是同构的

我已经成功创建了一个证明 Nat 可以转换为 Vec 的函数:

ℕ→vec : (n : ℕ) → Vec ⊤ n
ℕ→vec  zero   = []
ℕ→vec (suc a) = tt ∷ ℕ→vec a

当我试图写一个相应的 vec→ℕ 时,我失败了。

我想写这样的东西(不能编译但可读):

vec→ℕ : ∀ {n} → Vec ⊤ n → (n : ℕ)
vec→ℕ  []      = zero
vec→ℕ (tt ∷ a) = suc (vec→ℕ a)

在第一段代码中,确保参数恰好是 return 值的长度。 但是,如何确保第一个参数的长度恰好是 return 值?

我不知道这是否是最好的解决方案,但这是我想出来的。

open import Data.Vec
open import Data.Unit
open import Data.Nat
open import Data.Product

open import Relation.Binary.PropositionalEquality

vec→ℕ : ∀ {n} → Vec ⊤ n → ∃ (λ m → n ≡ m)
vec→ℕ  []      = zero , refl
vec→ℕ (tt ∷ a) with vec→ℕ a
vec→ℕ (tt ∷ a) | m , refl = suc m , refl

我没有说结果恰好是 n,而是引入了一个等式来指定这样的函数 return 和 m,这样 n ≡ m.希望对您有所帮助。使用您的类型签名,我遇到了一个解析错误并开发了这个。

您可以使 vec→ℕ 在定义上等于长度:

vec→ℕ : ∀ {n} → Vec ⊤ n → ℕ
vec→ℕ {n} _ = n

然后我认为这对 Agda 来说是足够透明的,在任何你需要 属性 的地方,你得到的 是正确的,它会自动提供给你(即通过减少)。

编辑添加: 你可能认为这是未指定的,因为 vec→ℕ 的类型没有规定确切的 自然 returns。然而,Agda 看穿了这个定义,所以例如如果需要,您可以证明以下外部正确性证明(但我认为它不会增加任何价值):

open import Relation.Binary.PropositionalEquality

vec→ℕ-correct : ∀ {n} {xs : Vec ⊤ n} → vec→ℕ xs ≡ n
vec→ℕ-correct = refl

请注意,因为 vec→ℕ xs 在定义上等于 n,我们不需要在证明中查看 nxs