我试图在Coq中定义和证明一个有效区分两个排序列表的函数。因为它并不总是在结构较小的术语上递归(第一个或第二个列表较小),Fixpoint
不会接受它,所以我尝试使用Program Fixpoint
代替
当尝试使用策略simpl
或program_simpl
来证明函数的属性时,Coq会花费几分钟计算,然后产生一个巨大的术语,数百行。我想知道我是否以错误的方式使用Program Fixpoint
,或者在推理时是否应该使用其他策略而不是简化?
我也想知道在这样的参数中包含正确性所需的属性是否是一种好的做法,或者更好的是有一个单独的包装函数将正确性属性作为参数,并使这个函数正好把两个列表分开?
请注意,我确实尝试定义更简单的make_diff
版本,它只将l1和l2作为参数并修复了类型A
和关系R
,但这仍然产生了巨大的影响应用program_simpl
或simpl
策略时的术语。
*编辑:我的包括(虽然这里可能不是全部都需要):
Require Import Coq.Sorting.Sorted.
Require Import Coq.Lists.List.
Require Import Coq.Relations.Relation_Definitions.
Require Import Recdef.
Require Import Coq.Program.Wf.
Require Import Coq.Program.Tactics.
代码:
Definition is_decidable (A : Type) (R : relation A) := forall x y, {R x y} + {~(R x y)}.
Definition eq_decidable (A : Type) := forall (x y : A), { x = y } + { ~ (x = y) }.
Inductive diff (X: Type) : Type :=
| add : X -> diff X
| remove : X -> diff X
| update : X -> X -> diff X.
Program Fixpoint make_diff (A : Type)
(R : relation A)
(dec : is_decidable A R)
(eq_dec : eq_decidable A)
(trans : transitive A R)
(lt_neq : (forall x y, R x y -> x <> y))
(l1 l2 : list A)
{measure (length l1 + length l2) } : list (diff A) :=
match l1, l2 with
| nil, nil => nil
| nil, (new_h::new_t) => (add A new_h) :: (make_diff A R dec eq_dec trans lt_neq nil new_t)
| (old_h::old_t), nil => (remove A old_h) :: (make_diff A R dec eq_dec trans lt_neq old_t nil)
| (old_h::old_t) as old_l, (new_h::new_t) as new_l =>
if dec old_h new_h
then (remove A old_h) :: make_diff A R dec eq_dec trans lt_neq old_t new_l
else if eq_dec old_h new_h
then (update A old_h new_h) :: make_diff A R dec eq_dec trans lt_neq old_t new_t
else (add A new_h) :: make_diff A R dec eq_dec trans lt_neq old_l new_t
end.
Next Obligation.
Proof.
simpl.
generalize dependent (length new_t).
generalize dependent (length old_t).
auto with arith.
Defined.
Next Obligation.
Proof.
simpl.
generalize dependent (length new_t).
generalize dependent (length old_t).
auto with arith.
Defined.
答案 0 :(得分:2)
在这种特殊情况下,我们可以摆脱value
并使用简单的<input type="submit" name="somePostParamName" th:value="${titulo}" />
。因为在每次递归调用时,我们在第一个列表的尾部或第二个列表的尾部调用Program Fixpoint
,我们可以嵌套两个定点函数,如下所示。 (我在这里使用Fixpoint
机制来避免传递太多相同的参数)
make_diff
观察Section
机制不会在结果签名中包含未使用的参数。这是一个天真的测试:
Require Import Coq.Lists.List.
Import ListNotations.
Require Import Coq.Relations.Relations.
Section Make_diff.
Variable A : Type.
Variable R : relation A.
Variable dec : is_decidable A R.
Variable eq_dec : eq_decidable A.
Variable trans : transitive A R.
Variable lt_neq : forall x y, R x y -> x <> y.
Fixpoint make_diff (l1 l2 : list A) : list (diff A) :=
let fix make_diff2 l2 :=
match l1, l2 with
| nil, nil => nil
| nil, new_h::new_t => (add A new_h) :: make_diff2 new_t
| old_h::old_t, nil => (remove A old_h) :: make_diff old_t nil
| old_h::old_t, new_h::new_t =>
if dec old_h new_h
then (remove A old_h) :: make_diff old_t l2
else if eq_dec old_h new_h
then (update A old_h new_h) :: make_diff old_t new_t
else (add A new_h) :: make_diff2 new_t
end
in make_diff2 l2.
End Make_diff.
答案 1 :(得分:1)
对于任何遇到过这种情况的人来说,现在更好的替代方案是Equations插件,它最终将取代功能和程序修复点。