这样做可以默认带来可决定性,为计算证明打开更多机会,并通过避免证明引擎携带大型证明项来提高检查性能。您不必像
Edwin Brady的论文中描述的那样携带大型术语以实现“强制优化”。Agda确实具有影响类型检查的强制性(特别是如何计算宇宙是相关的),但我不确定仅在类型检查时间使用的东西是否在运行时之前真正被删除。无论如何,Agda有两个不相关的概念:
.(eq : p ≡ q)
是通常的不相关性(意味着
eq
在类型检查时间是不相关的,因此在该类型的任何其他术语方面定义上等同),而
..(x : A)
是脊柱不相关性(不确定是否是正确的术语。我认为Agda源将这种事情称为“非严格不相关性”),其字面上是用于擦除计算上不相关但不完全不相关的术语。所以你可以定义
data Vec {α} (A : Set α) : ..(n : ℕ) -> Set α where
[] : Vec A 0
_∷_ : ∀ ..{n} -> A -> Vec A n -> Vec A (suc n)
在运行时之前,n
将被清除。至少看起来是这样设计的,但很难确定,因为 Agda 有许多文档不完善的功能。
你可以在 Coq 中编写那些零成本证明,只是因为它也实现了 Prop
中的无关性。但是,在 Coq 的理论中,无关性已经深入内部,而在 Agda 中,它是一个单独的功能,因此可以理解为什么人们更容易在 Coq 中使用无关性。
SSReflect 的方法的一个优点是它允许重用,因此例如对于 seq
定义的许多函数和关于它们的证明仍然可以与 tuple
一起使用(通过操作基础的 seq
),而使用 Idris 的方法则需要为 Vect
重新编写像 reverse、append 等函数。
如果您必须证明的属性与针对索引数据定义的函数具有相同的复杂度,那么重用实际上并不是真正的重用。而且,要做一个统一机器的工作并传递显式证明以及应用引理来从 suc (length xs) ≡ n 推导出 length xs ≡ n(以及 sym、trans、subst 和所有其他统一机器可以在许多情况下为您节省的引理)也很不方便。此外,通过滥用命题等式,您会失去一些清晰度:在上下文中具有 xs : List A; length xs ≡ n + m 而不是 xs : Vec A (n + m) 并不会提高可读性,特别是如果它们很大,这种情况经常发生。还有另一个问题:有时使用SSReflect的方法定义函数更加困难:您提到了 Vect 的 reverse,我向您挑战,从零开始定义此函数(使用 List 的 reverse 作为底层“重用”部分),然后将您的解决方案与 Agda 标准库中 Data.Vec 的定义进行比较。如果您没有默认启用命题的不相关性(这是 Agda 的情况),那么如果您想证明 reverse (reverse xs) ≡ xs 等属性,则还需要证明有关证明的属性,这是很多非平凡样板文件。
所以 SSReflect 的方法并不完美,另一个方法也是如此。有没有什么东西可以改进两者?是的,有装饰(见
Ornamental Algebras, Algebraic Ornaments 和
The essence of ornaments)。你可以通过应用相应的装饰代数轻松地从
List
获取
Vec
,但我无法说你能从中获得多少代码重用以及类型是否会让你烦恼。我听说有人实际上在某个地方使用装饰。
因此,并不是我们拥有理想的 SSReflect 解决方案,而其他人拒绝采用它。只是希望有更合适的方式来实现实际的代码重用。
更新
Anton Trunov在他的评论中让我意识到我有点太过于Agda思维,而Coq中的人们有可以简化证明的策略,因此在Coq中进行证明通常比对数据定义的函数进行定义更容易(前提是您拥有像CPDT书中的crush
这样的武器)。好吧,那么我想默认的证明不相关性和繁重的策略机制就是使SSReflect方法在Coq中有效的原因。
reverse
函数很容易:Definition trev T n (t : n.-tuple T) := [tuple of rev t]。
在这里,我们重用了列表的rev
函数(在ssr中称为seq
)。证明trev
是自反的也很容易:Lemma trevK T n : involutive (@trev T n). Proof. by move=>t; apply: val_inj; rewrite /= revK. Qed.
在这里,我们再次重用了列表的revK
,并使用了非平凡部分的证明不可知性引理val_inj
。 - Anton Trunovrev
。 - Anton Trunovval_inj
引理来剥离_:size tval == n
部分。在SSReflect中,==
表示布尔可决等式,我们操作nat
,因此val_inj
移除了元组的无关证明部分,并让我们处理底层列表,以便我们可以重用列表引理。这里是一个包含所有导入的gist。 - Anton Trunovrewrite
和apply
),但可决性肯定起着重要作用。 - Anton Trunov