证明在 Coq 提取中的作用
Proofs' role in Coq extractions
我试图了解证明在 Coq 提取中的作用。
我有以下取自 here 的整数除以二的示例。对于我的第一次尝试,我使用了 Admitted
关键字:
(*********************)
(* div_2_even_number *)
(*********************)
Definition div_2_even_number: forall n,
(Nat.Even n) -> {p:nat | n=p+p}.
Proof.
Admitted.
(*************)
(* test_even *)
(*************)
Definition test_even: forall n,
{Nat.Even n}+{Nat.Even (pred n)}.
Proof.
Admitted.
(********************)
(* div_2_any_number *)
(********************)
Definition div_2_any_number (n:nat):
{p:nat | n = p+p}+{p:nat | (pred n) = p+p} :=
match (test_even n) with
| left h => inl _ (div_2_even_number n h)
| right h' => inr _ (div_2_even_number (pred n) h')
end.
(***************************)
(* Extract to Haskell file *)
(***************************)
Extraction "/home/oren/some_file.hs" div_2_any_number.
当我检查生成的 Haskell 文件时,我发现它确实丢失了:
div_2_even_number :: Prelude.Integer -> Prelude.Integer
div_2_even_number =
Prelude.error "AXIOM TO BE REALIZED"
test_even :: Prelude.Integer -> Prelude.Bool
test_even =
Prelude.error "AXIOM TO BE REALIZED"
div_2_any_number :: Prelude.Integer -> Prelude.Either Prelude.Integer
Prelude.Integer
div_2_any_number n =
case test_even n of {
Prelude.True -> Prelude.Left (div_2_even_number n);
Prelude.False -> Prelude.Right (div_2_even_number (pred n))}
所以我想好吧,让我们来证明div_2_even_number
:
(*********************)
(* div_2_even_number *)
(*********************)
Definition div_2_even_number: forall n,
(Nat.Even n) -> {p:nat | n=p+p}.
Proof.
intros n0 H.
unfold Nat.Even in H.
destruct H as [m0].
exists m0.
Qed.
但我收到以下错误:
Error: Case analysis on sort Set is not allowed for inductive definition ex.
这是怎么回事?我显然在这里遗漏了一些东西。
您正在处理不同种类的类型。
> Check (Nat.Even 8).
Nat.Even 8
: Prop
> Check {p:nat | 8=p+p}.
{p : nat | 8 = p + p}
: Set
Coq 类型系统的一个特点是您不能消除类型在 Prop
中的值来获得类型不在 Prop
中的值(粗略地说 - 一些异常已经完成Coq 的 Prop
类型不携带任何信息,例如 True
和 False
,但我们不是那种情况)。粗略地说,你不能用一个命题的证明来证明另一个命题。
不幸的是,需要此限制才能使 Prop
成为非谓语(我们希望 forall P: Prop, P->P
成为排序 Prop
中的类型)并与排中律保持一致.我们不能拥有一切,否则我们会遇到 Berardi 的悖论。
虽然chi说的是对的,但是这种情况下其实可以从存在证明中提取witness p
。当你有一个布尔谓词 P : nat -> bool
时,如果 exists p, P p = true
,你可以通过 运行 以下函数从 0:
计算满足谓词的一些 p
find p := if P p then p else find (S p)
您不能直接在 Coq 中编写此函数,但可以通过精心设计一个特殊的归纳命题来实现。该模式在数学组件库的choice module中实现:
From mathcomp Require Import ssreflect ssrfun ssrbool ssrnat eqtype choice.
(* == is the boolean equality test *)
Definition even n := exists p, (n == 2 * p) = true.
Definition div_2_even_number n (nP : even n) : {p | (n == 2 * p) = true} :=
Sub (xchoose nP) (xchooseP nP).
xchoose : (exists n, P n = true) -> nat
函数执行上述搜索,xchooseP
表明其结果满足布尔谓词。 (实际类型比这更通用,但当实例化为 nat
时,它们会产生此签名。)我使用布尔相等运算符来简化代码,但本来可以使用 =
相反。
也就是说,如果您关心 运行 您的代码,以这种方式编程是非常低效的:您需要执行 n / 2
nat
比较来测试除法 n
.编写除法函数的简单类型版本要好得多:
Fixpoint div2 n :=
match n with
| 0 | 1 => 0
| S (S n) => S (div2 n)
end.
我试图了解证明在 Coq 提取中的作用。
我有以下取自 here 的整数除以二的示例。对于我的第一次尝试,我使用了 Admitted
关键字:
(*********************)
(* div_2_even_number *)
(*********************)
Definition div_2_even_number: forall n,
(Nat.Even n) -> {p:nat | n=p+p}.
Proof.
Admitted.
(*************)
(* test_even *)
(*************)
Definition test_even: forall n,
{Nat.Even n}+{Nat.Even (pred n)}.
Proof.
Admitted.
(********************)
(* div_2_any_number *)
(********************)
Definition div_2_any_number (n:nat):
{p:nat | n = p+p}+{p:nat | (pred n) = p+p} :=
match (test_even n) with
| left h => inl _ (div_2_even_number n h)
| right h' => inr _ (div_2_even_number (pred n) h')
end.
(***************************)
(* Extract to Haskell file *)
(***************************)
Extraction "/home/oren/some_file.hs" div_2_any_number.
当我检查生成的 Haskell 文件时,我发现它确实丢失了:
div_2_even_number :: Prelude.Integer -> Prelude.Integer
div_2_even_number =
Prelude.error "AXIOM TO BE REALIZED"
test_even :: Prelude.Integer -> Prelude.Bool
test_even =
Prelude.error "AXIOM TO BE REALIZED"
div_2_any_number :: Prelude.Integer -> Prelude.Either Prelude.Integer
Prelude.Integer
div_2_any_number n =
case test_even n of {
Prelude.True -> Prelude.Left (div_2_even_number n);
Prelude.False -> Prelude.Right (div_2_even_number (pred n))}
所以我想好吧,让我们来证明div_2_even_number
:
(*********************)
(* div_2_even_number *)
(*********************)
Definition div_2_even_number: forall n,
(Nat.Even n) -> {p:nat | n=p+p}.
Proof.
intros n0 H.
unfold Nat.Even in H.
destruct H as [m0].
exists m0.
Qed.
但我收到以下错误:
Error: Case analysis on sort Set is not allowed for inductive definition ex.
这是怎么回事?我显然在这里遗漏了一些东西。
您正在处理不同种类的类型。
> Check (Nat.Even 8).
Nat.Even 8
: Prop
> Check {p:nat | 8=p+p}.
{p : nat | 8 = p + p}
: Set
Coq 类型系统的一个特点是您不能消除类型在 Prop
中的值来获得类型不在 Prop
中的值(粗略地说 - 一些异常已经完成Coq 的 Prop
类型不携带任何信息,例如 True
和 False
,但我们不是那种情况)。粗略地说,你不能用一个命题的证明来证明另一个命题。
不幸的是,需要此限制才能使 Prop
成为非谓语(我们希望 forall P: Prop, P->P
成为排序 Prop
中的类型)并与排中律保持一致.我们不能拥有一切,否则我们会遇到 Berardi 的悖论。
虽然chi说的是对的,但是这种情况下其实可以从存在证明中提取witness p
。当你有一个布尔谓词 P : nat -> bool
时,如果 exists p, P p = true
,你可以通过 运行 以下函数从 0:
p
find p := if P p then p else find (S p)
您不能直接在 Coq 中编写此函数,但可以通过精心设计一个特殊的归纳命题来实现。该模式在数学组件库的choice module中实现:
From mathcomp Require Import ssreflect ssrfun ssrbool ssrnat eqtype choice.
(* == is the boolean equality test *)
Definition even n := exists p, (n == 2 * p) = true.
Definition div_2_even_number n (nP : even n) : {p | (n == 2 * p) = true} :=
Sub (xchoose nP) (xchooseP nP).
xchoose : (exists n, P n = true) -> nat
函数执行上述搜索,xchooseP
表明其结果满足布尔谓词。 (实际类型比这更通用,但当实例化为 nat
时,它们会产生此签名。)我使用布尔相等运算符来简化代码,但本来可以使用 =
相反。
也就是说,如果您关心 运行 您的代码,以这种方式编程是非常低效的:您需要执行 n / 2
nat
比较来测试除法 n
.编写除法函数的简单类型版本要好得多:
Fixpoint div2 n :=
match n with
| 0 | 1 => 0
| S (S n) => S (div2 n)
end.