Coq 以支柱居民为参数的不动点
考虑中Coq 以支柱居民为参数的不动点,coq,Coq,考虑中find的定义,它作为类型find:forall A:type,(A->bool)->list A->option A 当然,find必须返回选项A而不是A,因为我们不知道列表中是否有“有效”元素 现在,假设我发现find的这个定义很痛苦,因为我们必须处理这个选项,即使我们确定列表中存在这样的元素 因此,我想定义myFind,哪个additionnaly需要证明列表中有这样一个元素。可能是这样的: Variable A: Type. Fixpoint myFind (f: A -&g
find
的定义,它作为类型find:forall A:type,(A->bool)->list A->option A
当然,find
必须返回选项A
而不是A
,因为我们不知道列表中是否有“有效”元素
现在,假设我发现find
的这个定义很痛苦,因为我们必须处理这个选项,即使我们确定列表中存在这样的元素
因此,我想定义myFind
,哪个additionnaly需要证明列表中有这样一个元素。可能是这样的:
Variable A: Type.
Fixpoint myFind
(f: A -> bool)
(l: list A)
(H: exists a, In a l /\ f a = true): A :=
...
如果我没有弄错的话,这样的签名非正式地说:“给我一个函数,一个列表,并证明列表中有一个“有效”元素。”
我的问题是:我如何使用提供的假设并定义我的不动点
我的想法是:
match l with
| nil => (* Use H to prove this case is not possible *)
| hd :: tl =>
if f hd
then hd
else
(* Use H and the fact that f hd = false
to prove H': exists a, In a tl /\ f a = true *)
myFind f tl H'
end.
另一个好处是知道我是否可以直接在类型中嵌入关于结果的属性,例如,在我们的例子中,证明返回值
r
确实是这样的fr=true
我们可以通过输入列表上的结构递归来实现这个myFind
函数。在空列表的情况下,False\rect
归纳原则是我们的朋友,因为它让我们从逻辑世界切换到计算世界。一般来说,如果正在构造的术语的类型为类型
,我们不能破坏命题的证明,但是如果我们有不一致性,系统允许我们
我们可以通过使用护航模式(Stackoverflow上有许多很好的答案解释了这个模式)和一个辅助引理find\u not\u head
来处理非空输入列表的情况
我在下面的实现中使用了两次护航模式,这可能是有用的:顶层的模式用于让Coq知道输入列表在第一个match
-分支中是空的——注意H
的类型在两个分支中是不同的
From Coq Require Import List.
Import ListNotations.
Set Implicit Arguments.
(* so we can write `f a` instead of `f a = true` *)
Coercion is_true : bool >-> Sortclass.
Section Find.
Variables (A : Type) (f : A -> bool).
(* auxiliary lemma *)
Fact find_not_head h l : f h = false ->
(exists a, In a (h :: l) /\ f a) ->
exists a, In a l /\ f a.
Proof. intros E [a [[contra | H] fa_true]]; [congruence | now exists a]. Qed.
Fixpoint myFind (l : list A) (H : exists a : A, In a l /\ f a) : {r : A | f r} :=
match l with
| [] => fun H : exists a : A, In a [] /\ f a =>
False_rect {r : A | f r}
match H with
| ex_intro _ _ (conj contra _) =>
match contra with end
end
| h :: l => fun H : exists a : A, In a (h :: l) /\ f a =>
(if f h as b return (f h = b -> {r : A | f r})
then fun Efh => exist _ h Efh
else fun Efh => myFind l (find_not_head Efh H)) eq_refl
end H.
End Find.
下面是一个简单的测试:
From Coq Require Import Arith.
Section FindTest.
Notation l := [1; 2; 0; 9].
Notation f := (fun n => n =? 0).
Fact H : exists a, In a l /\ f a.
Proof. exists 0; intuition. Qed.
Compute myFind f l H.
(*
= exist (fun r : nat => f r) 0 eq_refl
: {r : nat | f r}
*)
End FindTest.
您还可以使用
Program
以交互方式帮助您构造证明参数。您可以在程序体中尽可能多地填写内容,并留下\uu
空白,以便稍后使用验证策略进行填写
Require Import List Program.
Section Find.
Variable A : Type.
Variable test : A -> bool.
Program Fixpoint FIND l (H:exists a, test a = true /\ In a l) : {r | test r = true} :=
match l with
| [] => match (_:False) with end
| a::l' => if dec (test a) then a else FIND l' _
end.
Next Obligation.
firstorder; congruence.
Defined.
End Find.
Program
在进行案例分析时能够更好地避免忘记信息(它知道护航模式),但它并不完美,因此在if
语句中使用dec
(请注意Coq是如何处理第一项义务的,即构造一个类型为False
的术语,这一切都是由它自己完成的!)