我正在构建一个在列表match
上执行l
的递归函数。在cons
分支中,我需要使用l = cons a l'
的信息来证明递归函数终止。但是,当我使用match l
时,信息会丢失。
如何使用match
来保存信息?
以下是函数(drop
和drop_lemma_le
在最后给出,以便于阅读):
Fixpoint picksome (l:list nat) (H : Acc lt (length l)) {struct H}: list nat.
refine (
match l with
nil => nil
| cons a l' => cons a (picksome (drop a l') _)
end
).
apply H.
assert (l = cons a l') by admit. (* here is where I need the information *)
rewrite H0.
simpl.
apply le_lt_n_Sm.
apply drop_lemma_le.
Defined. (* Can't end definition here because of the 'admit'. *)
我实际上能够通过refine
定义整个函数,如下所示,但它实际上并不可读。做Print picksome.
揭示了Coq如何处理这个问题,但是对于嵌套函数等来说它也很长并且不可读。
必须有一种更易读的方式来写它,对吧?
Fixpoint picksome (l:list nat) (H : Acc lt (length l)) {struct H}: list nat.
Proof.
refine ( _ ).
remember l as L.
destruct l as [| a l'].
apply nil.
apply (cons a).
apply (picksome (drop a l')).
apply H.
rewrite HeqL.
simpl.
apply le_lt_n_Sm.
apply drop_lemma_le.
Defined.
我的第一次尝试是尝试这样的事情
Definition list_cons_dec {T} (l:list T) :
{exists a l', l=a::l'} + {~ exists a l', l=a::l'}.
remember l as L.
destruct l as [| a l'].
- right; subst L; intros [a [A B]]; inversion B.
- left; exists a, l'; apply HeqL.
Defined.
Fixpoint picksome (l:list nat) (H : Acc lt (length l)) {struct H}: list nat.
Proof.
refine (
match list_cons_dec l with
| right Hdec => nil
| left Hdec => cons _ (picksome (drop _ _) _)
end
).
destruct l.
inversion Hdec. (* fails *)
我无法了解a
和l'
的实际l
和Error: Inversion would require case analysis on sort Set which is not allowed
for inductive definition ex.
。 Coq抱怨道:
drop
这样做的正确(可读)方法是什么?
以下是drop_lemma_le
和Fixpoint drop {T} n (l:list T) :=
match n with
| O => l
| S n' => match l with
| nil => nil
| cons _ l' => drop n' l'
end
end.
Lemma drop_lemma_le : forall {T} n (l:list T), length (drop n l) <= (length l).
Proof.
intros; generalize n;
induction l; intros; destruct n0; try reflexivity.
apply le_S; apply IHl.
Defined.
的定义。
{{1}}
答案 0 :(得分:7)
要记住你在模式匹配的列表中看起来像什么,你需要简单地改变匹配的返回类型。
Fixpoint picksome (l:list nat) (H : Acc lt (length l)) {struct H}: list nat.
refine (
(match l as m return l = m -> list nat with
nil => fun Hyp => nil
| cons a l' => fun Hyp => cons a (picksome (drop a l') _)
end) (eq_refl l)
).
这match l as m return l = m -> list nat
所说的是,您正在l
上执行模式匹配,您将调用匹配的表单m
,并且证明{{1}等于l
,你将构建一个nat列表。
现在,m
块的类型会略有不同:它不是仅提供match
,而是提供list nat
类型的函数。幸运的是,l = l -> list nat
提供了eq_refl l
等同于自己的证明,因此我们可以将匹配应用于该值并返回我们的初始l
。
看看比赛的分支,我们可以看到:
在list nat
案例中,您可以忽略您不需要的额外假设。
在nil
案例中,它为您提供了非常需要的假设,您可以履行证明义务:
cons
定义。