【问题标题】:Agda Type-Checking and Commutativity / Associativity of +Agda 类型检查和交换性 / + 的关联性
【发布时间】:2012-10-08 14:19:15
【问题描述】:

由于Nat_+_ 操作通常在第一个参数中递归定义,因此类型检查器知道i + 0 == i 显然不是微不足道的。然而,当我在固定大小的向量上编写函数时,我经常遇到这个问题。

一个例子:我如何定义一个 Agda 函数

swap : {A : Set}{m n : Nat} -> Vec A (n + m) -> Vec A (m + n)

将第一个n 值放在向量的末尾?

因为在 Haskell 中一个简单的解决方案是

swap 0 xs     = xs
swap n (x:xs) = swap (n-1) (xs ++ [x])

我在 Agda 中类似地尝试过这样的:

swap : {A : Set}{m n : Nat} -> Vec A (n + m) -> Vec A (m + n)    
swap {_} {_} {zero} xs          = xs 
swap {_} {_} {suc i} (x :: xs)  = swap {_} {_} {i} (xs ++ (x :: []))

但是类型检查器失败并显示消息(与上述swap-Definition 中的{zero}-case 相关):

.m != .m + zero of type Nat
when checking that the expression xs has type Vec .A (.m + zero)

那么,我的问题是:如何教 Agda,m == m + zero?以及如何在 Agda 中编写这样的swap 函数?

【问题讨论】:

  • 对于它的价值,我不会在你的 swap 签名中隐含自然(至少 n),因为 Agda 无法推断它。
  • @copumpkin:我可能是错的,但我认为类型检查器在某些情况下可以推断出这两种情况(取决于使用swap 的上下文)?
  • 据我所知没有。假设你有一个Vec Nat (5 + 3)。该添加将立即将类型减少到 Vec Nat 8,然后 Agda 将尝试将其与 Vec A (n + m) 统一,然后举起双手(即,将您的术语设为黄色),因为它不能神奇地做减法。我有理由相信,即使使用 Agda 的奇特米勒模式统一,也不会有任何情况下它可以从上下文中推断出 nm

标签: haskell functional-programming agda dependent-type


【解决方案1】:

教 Agda m == m + zero 并不难。例如,使用等式证明的标准类型,我们可以写出这样的证明:

rightIdentity : (n : Nat) -> n + 0 == n
rightIdentity zero = refl
rightIdentity (suc n) = cong suc (rightIdentity n)

然后我们可以告诉 Agda 使用 rewrite 关键字来使用这个证明:

swap : {A : Set} {m n : Nat} -> Vec A (n + m) -> Vec A (m + n)    
swap {_} {m} {zero} xs rewrite rightIdentity m = xs 
swap {_} {_} {suc i} (x :: xs) = ?

但是,为第二个等式提供必要的证明要困难得多。一般来说,尝试使您的计算结构与您的类型的结构相匹配是一个更好的主意。这样一来,您就可以少做很多定理证明(或者在这种情况下没有)。

例如,假设我们有

drop : {A : Set} {m : Nat} -> (n : Nat) -> Vec A (n + m) -> Vec A m
take : {A : Set} {m : Nat} -> (n : Nat) -> Vec A (n + m) -> Vec A n

(两者都可以在没有任何定理证明的情况下定义),Agda 会很高兴地接受这个定义,而不用大惊小怪:

swap : {A : Set} {m n : Nat} -> Vec A (n + m) -> Vec A (m + n)
swap {_} {_} {n} xs = drop n xs ++ take n xs

【讨论】:

  • 感谢您非常有帮助的回答!对我来说仍然很奇怪,函数的类型减少了实现函数的可能方法集;或者换句话说:习惯于用haskell编程,我从来没有这么认真地对待过类型。现在,我使用您建议的实现。但是,你能简单地勾勒一下如何教 agda,m == m + zero
  • @phynfo:我已经在回答的第一部分做了。如果您的意思是“无需告诉 Agda 何时使用它”,那么我认为您不能。另外,我从来没有说过不可能以你的方式定义它,只是要让 Agda 相信你的实现是正确的要困难得多。
  • 有一种方法可以使m + zero 神奇地减少为m,但它非常先进,您不能使用很多标准机器它。这个想法是将您的“单一”事物(此处为自然和加法)表示为差异结构(如差异列表),因此您的操作变为函数组合,而身份是身份函数。然后你携带一个不相关的差异不变量证明。你可以在这里找到更多信息:comments.gmane.org/gmane.comp.lang.agda/3259
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-14
  • 1970-01-01
  • 2019-03-17
  • 2012-01-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多