首页 > 解决方案 > 如何使用递减参数进行递归调用?

问题描述

Inductive bar {X : Type} : list X -> Prop :=
  | bar_nil : bar []
  | bar_fst : forall x l, bar (rev l ++ l) -> bar (rev l ++ [x] ++ l)
  | bar_snd : forall x l, bar (rev l ++ [x] ++ l) -> bar (rev l ++ [x; x] ++ l).

Axiom bar_surround :
  forall X x (l : list X),
  bar l -> bar ([x] ++ l ++ [x]).

Inductive list_last {X : Type} : list X -> Prop :=
  | ll_nil : list_last []
  | ll_snoc : forall l x, list_last l -> list_last (l ++ [x]).

Axiom ll_app :
  forall X (a b : list X),
  list_last a -> list_last b -> list_last (a ++ b).

Axiom ll_from_list :
  forall {X} (l : list X),
  list_last l.

Axiom app_head_eq :
  forall X (a b c : list X),
  a ++ c = b ++ c -> a = b.

Theorem foo :
  forall X (l: list X), l = rev l -> bar l.
Proof.
intros.
induction l.
- constructor.
- assert (Hll := ll_from_list l).
  inversion Hll.
  + apply (bar_fst x []). apply bar_nil.
  + rewrite <- H1 in H.
    simpl in H.
    rewrite rev_app_distr in H.
    rewrite <- app_assoc in H.
    simpl in H.
    inversion H.
    apply app_head_eq in H4.
    apply bar_surround.
1 subgoal
X : Type
x : X
l, l0 : list X
x0 : X
H : x :: l0 ++ [x0] = x0 :: rev l0 ++ [x]
IHl : l = rev l -> bar l
Hll : list_last l
H0 : list_last l0
H1 : l0 ++ [x0] = l
H3 : x = x0
H4 : l0 = rev l0
______________________________________(1/1)
bar l0

我离解决这个练习只有一步之遥,但我不知道如何做归纳步骤。请注意,这IHl在这里没有用,并且用 Induction on 替换 Induction lonHll也会有类似的问题。在这两种情况下,归纳假设都会期望一个减少一步的调用,而我需要两个 - 一个从等式两侧的列表的开头和结尾获取项目。

考虑一下我要证明的函数的类型是forall X (l: list X), l = rev l -> bar l并且我l0 = rev l0 -> bar l0的目标是在这里。l0是一个减少的参数,从而使递归调用安全。

我应该在这里做什么?

标签: coq

解决方案


您可以证明以下归纳谓词:

Inductive delist {A : Type} : list A -> Prop :=
| delist_nil : delist []
| delist_one x : delist [x]
| delist_cons x y l : delist l -> delist (x :: l ++ [y])
.

Theorem all_delist {A} : forall xs : list A, delist xs.

然后在你的最终定理中,归纳delist xs将分成你需要的情况。


另一种解决方案是对列表长度进行强归纳:

Lemma foo_len X : forall (n : nat) (l: list X), length l <= n -> l = rev l -> bar l.
Proof.
  induction n.
  (* Nat.le_succ_r from the Arith module is useful here *)
  ...
Qed.

(* Final theorem *)
Theorem foo X : forall (l : list X), l = rev l -> bar l.
Proof.
  intros; apply foo_len; auto.
Qed.

这是一个比 更常见和系统的原理delist,但是您需要比上面的 ad-hoc 归纳类型工作更多才能在主要证明中使用归纳假设。


推荐阅读