Coq QArith 除以零是零,为什么?

Coq QArith division by zero is zero, why?

我注意到在 Coq 的有理数定义中,零的倒数被定义为零。 (通常被零除不是well-defined/legal/allowed。)

Require Import QArith.
Lemma inv_zero_is_zero: (/ 0) == 0. 
Proof. unfold Qeq. reflexivity. Qed.

为什么会这样?

它会不会导致有理数计算出现问题,或者它是否安全?

简短的回答是:是的,绝对安全。

当我们说被零除没有明确定义时,我们实际上是指零没有乘法逆元。特别是,我们不能有一个函数来计算零的乘法逆元。但是, 可以编写一个函数来计算所有其他元素的乘法逆元,并且 return 可以在不存在这种逆元时使用某个任意值(例如,对于零)。这正是这个函数所做的。

在任何地方都定义了这个逆运算符意味着我们将能够定义其他用它计算的函数,而不必明确地争论它的参数不为零,从而使它使用起来更方便。确实,想象一下如果我们将这个函数 return 改为 option 会是多么痛苦,当我们将它传递给零时失败:我们将不得不使我们的整个代码成为一元代码,使其更难理解和理由。如果编写一个需要证明其参数非零的函数,我们会遇到类似的问题。

那么,有什么收获呢?好吧,当试图 证明 关于使用逆运算符的函数的任何事情时,我们将不得不添加明确的假设,说明我们正在向它传递一个不同于零的参数,或者争论它的参数可以 永远不会 为零。然后关于这个函数的引理得到额外的前提条件,例如

forall q, q <> 0 -> q * (/ q) = 1

许多其他库的结构与此类似,请参见。例如 MathComp 的代数库中 field axioms 的定义。

在某些情况下,我们希望将某些函数所需的附加前提条件内化为类型级约束。这就是我们在使用 length-indexed vectors 和一个安全的 get 函数时所做的,该函数只能在边界内的数字上调用。那么我们如何在设计库时决定使用哪一个,即是否使用具有大量额外信息的丰富类型并防止对某些函数的虚假调用(如在长度索引情况下)或将这些信息排除在外并要求它作为明确的引理(如在乘法逆的情况下)?好吧,这里没有明确的答案,确实需要单独分析每个案例并确定哪种替代方案更适合该特定案例。