使用Fix或Program Fixpoint在Coq中编写基础良好的程序
按照Chlipala一章中给出的示例,我正在尝试编写mergesort算法 这是我的密码使用Fix或Program Fixpoint在Coq中编写基础良好的程序,coq,Coq,按照Chlipala一章中给出的示例,我正在尝试编写mergesort算法 这是我的密码 Require Import Nat. Fixpoint insert (x:nat) (l: list nat) : list nat := match l with | nil => x::nil | y::l' => if leb x y then x::l else y::(insert x l
Require Import Nat.
Fixpoint insert (x:nat) (l: list nat) : list nat :=
match l with
| nil => x::nil
| y::l' => if leb x y then
x::l
else
y::(insert x l')
end.
Fixpoint merge (l1 l2 : list nat) : list nat :=
match l1 with
| nil => l2
| x::l1' => insert x (merge l1' l2)
end.
Fixpoint split (l : list nat) : list nat * list nat :=
match l with
| nil => (nil,nil)
| x::nil => (x::nil,nil)
| x::y::l' =>
let (ll,lr) := split l' in
(x::ll,y::lr)
end.
Definition lengthOrder (l1 l2 : list nat) :=
length l1 < length l2.
Theorem lengthOrder_wf : well_founded lengthOrder.
Admitted.
相反,可以使用命令程序固定点
或定义
,使用术语Fix
(如Chlipala书中所述)
然而,如果我写这个
Definition mergeSort : list nat -> list nat.
refine (Fix lengthOrder_wf (fun (l: list nat) => list nat)
(fun (l : list nat) => (fun mergeSort : (forall ls : list nat, lengthOrder ls l -> list nat )=>
if leb (length l) 1 then
let (ll,lr) := split l in
merge (mergeSort ll _) (mergeSort lr _)
else
l))).
我得到了不可能的目标:
2 subgoals, subgoal 1 (ID 65)
l : list nat
mergeSort : forall ls : list nat, lengthOrder ls l -> list nat
ll, lr : list nat
============================
lengthOrder ll l
subgoal 2 (ID 66) is:
lengthOrder lr l
这就是为什么Chlipala建议以这种方式更改mergeSort的定义:
Definition mergeSort : list nat -> list nat.
refine (Fix lengthOrder_wf (fun _ => list nat)
(fun (ls : list nat)
(mergeSort : forall ls' : list nat, lengthOrder ls' ls -> list nat) =>
if Compare_dec.le_lt_dec 2 (length ls)
then let lss := split ls in
merge (mergeSort (fst lss) _) (mergeSort (snd lss) _)
else ls)).
这将产生以下目标:
2 subgoals, subgoal 1 (ID 68)
ls : list nat
mergeSort : forall ls' : list nat, lengthOrder ls' ls -> list nat
l : 2 <= length ls
lss := split ls : list nat * list nat
============================
lengthOrder (fst lss) ls
subgoal 2 (ID 69) is:
lengthOrder (snd lss) ls
2个子目标,子目标1(ID 68)
ls:列出nat
合并排序:用于所有ls”:列出nat,长度排序器ls->列出nat
l:2很容易看出,为了得到栉孔扇贝的溶液,你需要做两个改变
1) 在执行split
时,您需要记住ll
和lr
来自split,否则它们将是一些任意列表,不可能比原始列表l
短
以下代码无法保存此类信息:
let (ll,lr) := split l in
merge (mergeSort ll _) (mergeSort lr _)
因此,需要用
let lss := split ls in
merge (mergeSort (fst lss) _) (mergeSort (snd lss) _)
它保存了我们需要的东西
故障发生的原因是Coq无法记住ll
和lr
来自split l
,这是因为let(ll,lr)
只是伪装的match
(参见手册,)
回想一下,模式匹配的目的是(粗略地说)
- 解包归纳数据类型的某个值的组件,并将它们绑定到某些名称上(我们需要在我的答案的第二部分中使用它),然后
- 在相应的模式匹配分支中将原始定义替换为其特殊情况
现在,请注意,在我们对其进行模式匹配之前,split l
不会出现在目标或上下文中的任何位置。我们只是随意地把它引入定义中。这就是为什么模式匹配没有给我们任何东西——我们不能用目标或上下文中的“特殊情况”((ll,lr)
)替换拆分l
),因为任何地方都没有拆分l
通过使用逻辑相等(=
)还有一种替代方法:
这类似于使用记住策略。我们已经摆脱了fst
和snd
,但这是一个巨大的过度使用,我不推荐这样做
2) 我们需要证明的另一件事是,当2length(fst(split l))
可证明时,ll
和lr
比l
短!注意你有H:2谢谢你的回答。关键是Coq需要的所有假设都应该反映在表达式的类型中,因此,我们需要依赖的引理/结构来实现这一点。最后,这是直截了当的!对通常,与普通函数式编程相比,我们必须更明确地了解信息流。
let lss := split ls in
merge (mergeSort (fst lss) _) (mergeSort (snd lss) _)
(let (ll, lr) as s return (s = split l -> list nat) := split l in
fun split_eq => merge (mergeSort ll _) (mergeSort lr _)) eq_refl
Inductive sumbool (A B : Prop) : Set :=
left : A -> {A} + {B} | right : B -> {A} + {B}
Search (_ -> _ -> {_ <= _} + {_}).
(*
output:
le_lt_dec: forall n m : nat, {n <= m} + {m < n}
le_le_S_dec: forall n m : nat, {n <= m} + {S m <= n}
le_ge_dec: forall n m : nat, {n <= m} + {n >= m}
le_gt_dec: forall n m : nat, {n <= m} + {n > m}
le_dec: forall n m : nat, {n <= m} + {~ n <= m}
*)