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
的术语,这一切都是由它自己完成的!)