Coq Can';用非标准递归证明函数的平凡引理

Coq Can';用非标准递归证明函数的平凡引理,coq,coq-tactic,Coq,Coq Tactic,我很难证明关于我定义的函数的简单引理。这是我的定义: Require Import List. Require Export Omega. Require Export FunInd. Require Export Recdef. Notation "A :: B" := (cons A B). Notation "[]" := nil. Notation "[[ A ]]" := (A :: nil). Inductive tm := | E: nat -> tm | L: list

我很难证明关于我定义的函数的简单引理。这是我的定义:

Require Import List.
Require Export Omega.
Require Export FunInd.
Require Export Recdef.

Notation "A :: B" := (cons A B).
Notation "[]" := nil.
Notation "[[ A ]]" := (A :: nil).

Inductive tm :=
| E: nat -> tm
| L: list tm -> tm.

Definition T := list tm.

Fixpoint add_list (l: list nat) : nat :=
  match l with
  | [] => 0
  | n :: l' => n + (add_list l')
  end.

Fixpoint depth (t: tm) : nat :=
  match t with
  | E _ => 1
  | L l => 1 + (add_list (map depth l))
  end.

Definition sum_depth (l: T) := add_list (map depth l).

Function sum_total (l: T) {measure sum_depth l} : nat :=
  match l with
  | [] => 0
  | [[E n]] => n
  | [[L li]] => sum_total li
  | E n :: l' => n + (sum_total l')
  | L li :: l' => (sum_total li) + (sum_total l')
  end.
Proof.
  - auto.
  - intros; unfold sum_depth; subst. simpl; omega.
  - intros; subst; unfold sum_depth; simpl; omega.
  - intros; subst; unfold sum_depth; simpl; omega.
  Defined.
感应类型无法更改


我可以用计算策略来证明一些简单的命题,比如
引理测试:forall n,sum_total[[en]]]=n.
,但是另一个简单的引理,比如
引理测试2:forall l,sum_total[[l]=sum_total l.
挂起。

首先,似乎
计算策略“挂起”了你提到的目标(因为当使用
函数…证明…定义。
定义方法时,您的函数
sum\u total
包含一些不打算计算的证明项− 更重要的是一个任意的参数
l
;也许这样的策略更适合这种情况)

独立于我的,我仔细查看了您的形式化,在您的情况下似乎不需要
函数
命令,因为
总和
基本上是结构化的,因此您可以使用一个
固定点
,前提是您正在查看的归纳类型稍微重新表述为一次定义为相互的明确定义的归纳类型(参见相应的文档,其中给出了“树/森林”的类似典型示例)

为了详细说明您的示例,您可能希望调整您的定义(如果您的用例可能的话),如下所示:

Inductive tm :=
| E: nat -> tm
| L: T -> tm

with T :=
  Nil : T
| Cons : forall (e : tm) (l : T), T.

Notation "[[ A ]]" := (Cons A Nil).

Fixpoint sum_total (l: T) {struct l} : nat :=
  match l with
  | Nil => 0
  | [[E n]] => n
  | [[L li]] => sum_total li
  | Cons (E n) l' => n + (sum_total l')
  | Cons (L li) l' => (sum_total li) + (sum_total l')
  end.

(* and the lemma you were talking about is immediate *)
Lemma test2 : forall l, sum_total [[L l]] = sum_total l.
reflexivity.
Qed.
否则(如果您不能像这样重新表述您的
tm
归纳法),另一种解决方案是使用
函数
以外的另一种策略来定义您的
总和
函数,例如,或插件(在处理非结构化递归/依赖类型的模式匹配时,它们比
函数
灵活和健壮得多)

编辑:由于OP提到感应类型本身不能更改,因此有一个直接的解决方案,即使仅使用
功能
机械:依靠定义自动生成的“方程引理”

更准确地说,如果您按原样使用脚本,那么您将“免费”获得以下引理:

因此,您可以通过以下操作轻松陈述并证明您感兴趣的引理:

Lemma test2 : forall l, sum_total [[L l]] = sum_total l.
intros l.
rewrite sum_total_equation.
reflexivity.
Qed.

这是一个不需要改变电感类型的答案

sum\u total
有一个简单的定义,它既相对容易理解,又(几乎)给出了您通过
compute
寻找的引理

Fixpoint sum_tm (t : tm) : nat :=
  match t with
  | E n => n
  | L li => list_sum (map sum_tm li)
  end.
Definition sum_total (l : T) : nat := list_sum (map sum_tm l).

Lemma test2 : forall l, sum_total [[L l]] = sum_total l + 0.
reflexivity.
Qed.
list\u sum
来自
list
模块。)

请注意,
sum\u tm
sum\u total
的定义是如何精确地遵循
术语和
T
的定义结构的,其中
list\u sum
(由
map
组成)对应于使用
列表
。此模式通常对嵌套归纳法的这些问题有效

如果您想摆脱
+0
,您可以定义一个不同版本的
列表_sum
,其中包括一个单件列表的案例(如果您愿意,您可以将其与
映射
融合,尽管这不是必需的)

这看起来像是将
list\u sum
替换为
list\u sum\u alt
定义为

Fixpoint list_sum_alt (l : list nat) : nat :=
  match l with
  | [] => 0
  | [[n]] => n
  | n :: li => n + list_sum_alt li
  end.

根据这个定义,
test2
compute

保存,而不是编写
符号“[[A]]”:=(A::nil)。
,您可能需要依赖本模块中提供的符号:感谢您提供了快速、良好的答复,不幸的是,我无法更改归纳类型(我将修改我的问题以反映这一点),同时我将尝试一种不同的策略。
Fixpoint sum_tm (t : tm) : nat :=
  match t with
  | E n => n
  | L li => list_sum (map sum_tm li)
  end.
Definition sum_total (l : T) : nat := list_sum (map sum_tm l).

Lemma test2 : forall l, sum_total [[L l]] = sum_total l + 0.
reflexivity.
Qed.