如何证明Vec展开逆转?

时间:2014-11-10 10:04:43

标签: agda

Agda标准库有一些关于reverse_++_如何处理List的属性。试图将这些证据转移到Vec似乎是非平凡的(无视宇宙):

open import Data.Nat
open import Data.Vec
open import Relation.Binary.HeterogeneousEquality

unfold-reverse : {A : Set} → (x : A) → {n : ℕ} → (xs : Vec A n) →
                 reverse (x ∷ xs) ≅ reverse xs ++ [ x ]

TL; DR:如何证明unfold-reverse

本问题的其余部分概述了这样做的方法并解释了哪些问题浮出水面。

此属性的类型与List中的Data.List.Properties计数器部分非常相似。证据涉及帮助者,大致翻译为:

open import Function

helper : ∀ {n m} → (xs : Vec A n) → (ys : Vec A m) →
         foldl (Vec A ∘ (flip _+_ n)) (flip _∷_) xs ys ≅ reverse ys ++ xs

尝试在unfold-reverse中插入此帮助程序失败,因为左侧reversefoldl应用程序,Vec A ∘ suc作为第一个参数,而helper的左侧是{{ 1}}有foldl个应用程序,Vec A ∘ (flip _+_ 1)作为第一个参数。尽管suc ≗ flip _+_ 1可以随时使用Data.Nat.Properties.Simple,但由于此处cong需要非逐点相等而无需进一步假设,因此我们无法使用flip

flip _+_ n中的helper移除{{1}}会产生类型错误,因此也无法选择。

还有其他想法吗?

1 个答案:

答案 0 :(得分:2)

Data.Vec.Properties模块包含此功能:

foldl-cong : ∀ {a b} {A : Set a}
               {B₁ : ℕ → Set b}
               {f₁ : ∀ {n} → B₁ n → A → B₁ (suc n)} {e₁}
               {B₂ : ℕ → Set b}
               {f₂ : ∀ {n} → B₂ n → A → B₂ (suc n)} {e₂} →
             (∀ {n x} {y₁ : B₁ n} {y₂ : B₂ n} →
                y₁ ≅ y₂ → f₁ y₁ x ≅ f₂ y₂ x) →
             e₁ ≅ e₂ →
             ∀ {n} (xs : Vec A n) →
             foldl B₁ f₁ e₁ xs ≅ foldl B₂ f₂ e₂ xs
foldl-cong           _     e₁=e₂ []       = e₁=e₂
foldl-cong {B₁ = B₁} f₁=f₂ e₁=e₂ (x ∷ xs) =
  foldl-cong {B₁ = B₁ ∘ suc} f₁=f₂ (f₁=f₂ e₁=e₂) xs

这或多或少都是详细解决方案:

unfold-reverse : {A : Set} → (x : A) → {n : ℕ} → (xs : Vec A n) →
                 reverse (x ∷ xs) ≅ reverse xs ++ (x ∷ [])
unfold-reverse x xs = begin
  foldl (Vec _ ∘ _+_ 1) (flip _∷_) (x ∷ []) xs
    ≅⟨ (foldl-cong
         {B₁ = Vec _ ∘ _+_ 1}
         {f₁ = flip _∷_}
         {e₁ = x ∷ []}
         {B₂ = Vec _ ∘ flip _+_ 1}
         {f₂ = flip _∷_}
         {e₂ = x ∷ []}
         (λ {n} {a} {as₁} {as₂} as₁≅as₂ -> {!!})
         refl
         xs) ⟩
  foldl (Vec _ ∘ flip _+_ 1) (flip _∷_) (x ∷ []) xs
    ≅⟨ helper (x ∷ []) xs  ⟩
  reverse xs ++ x ∷ []
  ∎

请注意,B₁函数的参数中只有B₂foldl-cong不同。在简化了洞中的上下文之后我们

Goal: a ∷ as₁ ≅ a ∷ as₂
————————————————————————————————————————————————————————————
as₁≅as₂ : as₁ ≅ as₂
as₂     : Vec A (n + 1)
as₁     : Vec A (1 + n)
a       : A
n       : ℕ
A       : Set

所以我们需要证明,在每次递归调用时,向Vec A (n + 1)类型的累加器添加一个元素等于将一个元素添加到类型为Vec A (1 + n)的累加器中,然后将结果添加到两个{ {1}}是平等的。证明本身很简单。这是完整的代码:

foldl