英文:
Unable to unify "n * 0" with "0"
问题
我在《软件基础》的第一章。在尝试编写一个简单的定理时,出现了以下错误(这只是内置定理 mult_n_O
的一个实现):
Theorem mult_n_O' : forall n : nat, 0 = n * 0.
Proof. intros n. reflexivity. Qed.
我得到了错误消息:无法统一 "n * 0" 和 "0",出现在 reflexivity
步骤。请问有人可以解释这个错误,以及为什么当它与 mult_n_O
完全相同的定理时我会得到这个错误?
英文:
I'm in the first chapter of Software Foundation. In my attempt to write a simple theorem as follows (It is just an implementation of the built-in theorem mult_n_O
):
Theorem mult_n_O' : forall n : nat, 0 = n * 0.
Proof. intros n. reflexivity. Qed.
I got the error: Unable to unify "n * 0" with "0" At the reflexivity
step. Can someone please explain the error and why I get this error when it is the exact same theorem as mult_n_O
?
答案1
得分: 1
reflexivity
可以证明诸如5 = 5
或a + b = a + b
这样的命题,即等号两边在语法上相等的情况。
Coq还允许eta expansion
,即展开定义,以及beta reduction
,即将lambda表达式应用于参数,用于比较两个项是否相等。在Coq世界中,这被称为这些项在"convertible"。
现在,回到你的问题,n * 0
和0
不 是可转换的,因此你需要证明它们相等,这被称为propositionally equal。
为什么它们不可转换呢?嗯,如果你将*
扩展为mult
,得到mult n 0
,并将mult
替换为其定义,即
Definition mult := fix mul n m := match n with 0 => 0 | S n' => m + mul n' m end.
你会得到
(fix mul n m := match n with 0 => 0 | S n' => m + mul n' m end) n 0
然后进行beta reduction
(将lambda应用于其参数),你会得到类似于以下的项:
match n with 0 => 0 | S n' => 0 + mul n' 0 end
这不与0
在语法上相等。
在这里,内置的等价性检查("convertibility")停止了。它没有任何进一步简化match n with ...
的方法。(唯一的方法是如果被匹配的东西是一个归纳法的表达式,它会简化为以构造函数开始的东西,而不是函数或变量)
由于可转换性检查无法解决这个问题,你必须想出另一种证明等价性的方法。
为了做到这一点,你可以使用比纯粹的可转换性更强大的工具。你可以应用定理(归纳法或mult_n_0),折叠表达式等等。但是这种强大的功能意味着很难自动搜索证明,需要一些创造力。
当然,有一些人已经制作了带有有用启发式的策略("coq commands"),它们尝试许多有用的技巧,通常可以起作用,但reflexivity
不是其中之一。它只寻找可转换性(以及其他一些与此无关的东西)。
希望这解释了"为什么它不起作用"。
英文:
reflexivity
can prove things like 5 = 5
or a + b = a + b
, that is, where both sides of the equal sign are syntactically equal.
Coq also allows eta expansion
, i.e. unfolding of defintion, and beta reduction
i.e. applying a lambda expression to an argument, when comparing if two terms are equal. This is called that the terms are convertible
in the Coq world.
Now, back to your question, n * 0
and 0
are not convertible, so you need to prove that they are equal, which is called being propositionally equal.
Why are they not convertible? Well, if you expand *
to mult
to get mult n 0
and replace mult
with its definition, which is
Definition mult := fix mul n m := match n with 0 => 0 | S n' => m + mul n' m end.
you have
(fix mul n m := match n with 0 => 0 | S n' => m + mul n' m end) n 0
and next do beta reduction
(applying the lambda on its args), you (kind of) get the term
match n with 0 => 0 | S n' => 0 + mul n' 0 end
which is not syntactically equal to 0
.
And here the builtin equivalence check ("convertibility") stops. It does not have any way of simplifying the match n with ...
any more. (The only way to do that is if the thing that was being matched on was an expression that reduced to something that starts with a constructor, not a function or a variable)
Since the convertibility check doesn't solve it, you have to come up with another way to prove the equivalence.
To do that, you have more powerful tools at your hands than plain convertibility. You can apply theorems (induction, or mult_n_0), fold expressions, etc. But that power means that it is hard to search for the proof automatically, and some ingenuity is needed.
There are of course some who have made tactics ("coq commands") with useful heuristics, that try a number of useful tricks that "often work", but reflexivity
is not one of them. It just looks for convertibility (and a little more, which is besides the point here).
I hope this explains "why it doesn't work".
答案2
得分: 0
对于Coq,n * 0
和 0
是不同的项,它们不能通过(语法)统一化变成相等,因此会出现错误消息。
但是,你可以通过对 n
进行归纳来证明这个定理,这将创建两个新的目标,一个是对 n = 0
,另一个是对 "n + 1",即 S n
或 n.+1
,假设定理对 n
成立(归纳假设)。
编辑(回答评论)
一个简单的逐步解决方案可以如下(我使用的是ssreflect,其中归纳是通过 elim
策略执行的,但你应该能理解这个思路)。
From mathcomp Require Import all_ssreflect.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Theorem mult_n_O' : forall n : nat, 0 = n * 0.
Proof.
elim.
- by [].
- move=> n IH.
by rewrite mulSnr -IH.
Qed.
注意使用 IH 将 n * 0
重写为 0
。
由于ssreflect提供了相当多的自动化功能,这可以简化为
Theorem mult_n_O'' : forall n : nat, 0 = n * 0.
Proof. by elim. Qed.
英文:
For Coq, n * 0
and 0
are different terms, which cannot be made equal by (syntactic) unification, hence the error message.
You can, however, prove this theorem by using induction on n
, which is going to create two new goals, one for n = 0
, and the other for "n + 1", i.e., S n
or n.+1
, assuming that the theorem holds for n
(the induction hypothesis).
EDITED (answering comments)
A simple step-by-step solution can be as follows (I'm using ssreflect, where induction is performed via the elim
tactic, but you should get the idea).
From mathcomp Require Import all_ssreflect.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Theorem mult_n_O' : forall n : nat, 0 = n * 0.
Proof.
elim.
- by [].
- move=> n IH.
by rewrite mulSnr -IH.
Qed.
Note the use of IH to rewrite n * 0
as 0
.
Since ssreflect offers quite a bit of automation, this can be simplified to
Theorem mult_n_O'' : forall n : nat, 0 = n * 0.
Proof. by elim. Qed.
答案3
得分: 0
"mult_n_O" 存在意味着你的定理是可证明的。但是有多种方法来证明不同的陈述。当两个等式的成员在内在计算规则下相同时,策略 "reflexivity" 只能用于此。对于你的陈述,没有计算规则能使其生效,因此 "reflexivity" 失效。
什么是 "内在计算规则"?它们追溯到乘法是如何定义的,我不打算在这里详细讨论这个问题。你应该进一步阅读软件基础知识。
但现在有了这个定理 "mult_n_O",我们如何使用它?它在软件基础知识书中有展示。使用它的方法是 "rewrite"(在你的情况下也可以使用 "apply")。
总结教训:重点不仅是知道哪些事实是真实的,而且要理解这些事实如何从基本定义或已经被证明的其他定理中可证明。这个 "如何" 依赖于几种技巧,每种技巧都体现在其中一个命令中,名为 "reflexivity" 或 "rewrite"。最好理解它们各自的作用。软件基础知识书很好地逐步阐述了它们的使用。
还有更强大的命令,将尝试多种方法来解决问题。但书中使用的教育过程更倾向于让你首先学习基本工具,然后再熟悉强大的工具。这个教育过程使你了解关于证明是什么的基本思想,这将在长期内有用。
英文:
The fact that mult_n_O
exists makes that your theorem is provable. But there are several ways to prove different statements. The tactic reflexivity
can only be used when the two members of an equality are the same modulo the intrinsic computation rules. In the case of your statement, no computation rule makes it work, so reflexivity
fails.
What are the intrinsic computation rules? They trace back to how multiplication was defined, and I don't wish to dwell on this here. You should read the software foundations further.
But now, there is this theorem mult_n_O
, how do we use it? It is shown in the software foundations book. The method to use it is rewrite
(in you case you could also use apply
).
The takeaway lesson: the point is not only to know what facts are true, but understand how these facts are provable from the basic definitions, or from other theorems that have already been proven. This "how" relies on several techniques, each of these techniques is embodied in one of these commands, named reflexivity
or rewrite
. It is better to understand what each of them does. The Software Foundations book does a good job of illustrating their use progressively.
There are also more powerful commands, that will try several methods to solve the problem. But the pedagogical process used in the book prefers to let you learn the basic tools first before getting acquainted with the powerful ones later. This pedagogical process makes you discover elementary ideas about what is a proof that will be useful in the long run.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论