我正在学习Coq。我陷入了一个非常愚蠢的问题(没有动力,真的很傻)。我想构建一个从2,+ oo]到映射x到x-3的整数集的函数。这应该很简单......在我知道的任何语言中,它很简单。但不是在Coq。首先,我写(我解释了很多细节,以便有人可以解释我在Coq的行为中不理解的东西)
Definition f : forall n : nat, n > 2 -> nat.
我得到一个子目标
============================
forall n : nat, n > 2 -> nat
这意味着Coq需要从n> 2的证明到整数集的映射。精细。所以我想告诉它n = 3 + p对于某个整数p,然后返回整数p。我写道:
intros n H.
我得到了上下文/子目标
n : nat
H : n > 2
============================
nat
然后我想我已经证明n = 3 + p对于某个整数p
cut(exists p, 3 + p = n).
我得到了上下文/子目标
n : nat
H : n > 2
============================
(exists p : nat, 3 + p = n) -> nat
subgoal 2 (ID 6) is:
exists p : nat, 3 + p = n
我通过
在上下文中移动假设intro K.
我获得:
n : nat
H : n > 2
K : exists p : nat, 3 + p = n
============================
nat
subgoal 2 (ID 6) is:
exists p : nat, 3 + p = n
我稍后会证明p的存在。现在我想通过精确的p完成证明。所以我首先需要做一个
destruct K as (p,K).
我收到错误消息
错误:对于归纳,不允许对排序集进行案例分析 定义ex。
我被困住了。
答案 0 :(得分:5)
你是对的!用任何合理的编程语言编写这个函数都应该很容易,而且幸运的是,Coq也不例外。
在您的情况下,通过忽略您提供的证明参数来定义您的函数要容易得多:
Definition f (n : nat) : nat := n - 3.
然后你可能想知道“但是等一下,自然数字在减法下不会被关闭,所以这有什么意义呢?”好吧,在Coq中,对自然数的减法并不是真正的减法:它实际上是截断。如果你试图从2减去,比如说3,你会得到0作为答案:
Goal 2 - 3 = 0. reflexivity. Qed.
这在实践中意味着你总是被允许“减去”两个自然数并得到一个自然数,但为了使这个减法有意义,第一个参数需要大于第二个参数。然后我们得到以下的引理(在standard library中可用):
le_plus_minus_r : forall n m, n <= m -> n + (m - n) = m
在大多数情况下,使用部分正确的函数(例如此减法定义)就足够了。但是,如果您愿意,可以限制f
的域以使其属性更加舒适。我冒昧地使用ssreflect库执行以下脚本,这使得编写此类函数变得更容易:
Require Import Ssreflect.ssreflect Ssreflect.ssrfun Ssreflect.ssrbool.
Require Import Ssreflect.ssrnat Ssreflect.eqtype.
Definition f (n : {n | 2 < n}) : nat :=
val n - 3.
Definition finv (m : nat) : {n | 2 < n} :=
Sub (3 + m) erefl.
Lemma fK : cancel f finv.
Proof.
move=> [n Pn] /=; apply/val_inj=> /=.
by rewrite /f /= addnC subnK.
Qed.
Lemma finvK : cancel finv f.
Proof.
by move=> n; rewrite /finv /f /= addnC addnK.
Qed.
现在,f
将自然数n
作为参数,大于2
({x : T | P x}
形式是sig
类型的语法糖来自标准库,用于形成类似子集的类型)。通过限制参数类型,我们可以编写一个反函数finv
,它采用任意nat
并返回另一个大于2
的数字。然后,我们可以证明lemmas fK
和finvK
,它们断言fK
和finvK
是彼此相反的。
关于f
的定义,我们使用val
,这是ssreflect的习惯用法,用于从{n | 2 < n}
类型的成员中提取元素。 Sub
finv
上的n
功能恰恰相反,使用2 < n
的证明打包自然数{n | 2 < n}
并返回<
元素。在这里,我们主要依赖于erefl
在ssreflect中表示为布尔计算的事实,因此Coq可以使用其计算规则来检查true = true
,2 < 3 + m
的证明,也是Type
的有效证明。
总而言之,您最终得到的神秘错误信息与Coq管理计算类型的规则有关,其中包含Prop
中的live和生成{p | 3 + p = n}
的命题类型。 Coq的规则禁止您使用命题证明来构建具有计算内容(例如自然数)的元素,除非在非常特殊的情况下。如果您愿意,您仍然可以使用exists p, 3 + p = n
代替Type
来完成定义 - 两者的意思相同,除了前者生活在Prop
中,而后者生活在{{1} }}