Coq can';使用重写策略时找不到子项

Coq can';使用重写策略时找不到子项,coq,theorem-proving,Coq,Theorem Proving,我正试图从具有依赖类型的认证编程版本中修改编译\u correct。在我的版本中,我试图利用progmenter是一个折叠的事实,并在证明privingcompile\u correct中的主要引理时使用较弱的归纳假设 与本书相同的代码为: Require Import Bool Arith List. Set Implicit Arguments. Inductive binop : Set := Plus | Times. Inductive exp : Set := | Const

我正试图从具有依赖类型的认证编程版本中修改
编译\u correct
。在我的版本中,我试图利用
progmenter
是一个折叠的事实,并在证明priving
compile\u correct
中的主要引理时使用较弱的归纳假设

与本书相同的代码为:

Require Import Bool Arith List.
Set Implicit Arguments.

Inductive binop : Set := Plus | Times.

Inductive exp : Set :=
  | Const : nat -> exp
  | Binop : binop -> exp -> exp -> exp.

Definition binopDenote (b : binop) : nat -> nat -> nat :=
  match b with
    | Plus => plus
    | Times => mult
  end.

Fixpoint expDenote (e : exp) : nat :=
  match e with
    | Const n => n
    | Binop b e1 e2 => (binopDenote b) (expDenote e1) (expDenote e2)
  end.

Inductive instr : Set :=
  | iConst : nat -> instr
  | iBinop : binop -> instr.

Definition prog := list instr.
Definition stack := list nat.

Definition instrDenote (i : instr) (s : stack) : option stack :=
  match i with
    | iConst n => Some (n :: s)
    | iBinop b =>
      match s with
        | arg1 :: arg2 :: s' => Some ((binopDenote b) arg1 arg2 :: s')
        | _ => None
      end
  end.

Fixpoint compile (e : exp) : prog :=
  match e with
    | Const n => iConst n :: nil
    | Binop b e1 e2 => compile e2 ++ compile e1 ++ iBinop b :: nil
  end.
然后我定义了我自己版本的
prog_-indicate
,它是程序中指令列表的折叠:

Definition bind {A B : Type} (a : option A) (f : A -> option B) : option B :=
  match a with
    | Some x => f x
    | None => None
  end.

Definition instrDenote' (s : option stack) (i : instr) : option stack :=
  bind s (instrDenote i).

Definition progDenote (p : prog) (s : stack) : option stack :=
  fold_left instrDenote' p (Some s).
然后,我试图证明书中的
compile\u correct
的较弱版本:

Lemma compile_correct' : forall e s,
  progDenote (compile e) s = Some (expDenote e :: s).
induction e.
intro s.
unfold compile.
unfold expDenote.
unfold progDenote at 1.
simpl.
reflexivity.
intro s.
unfold compile.
fold compile.
unfold expDenote.
fold expDenote.
unfold progDenote.
rewrite fold_left_app.
rewrite fold_left_app.
unfold progDenote in IHe2.
rewrite (IHe2 s).
unfold progDenote in IHe1.
rewrite (IHe1 (expDenote e2 :: s)).
我的证明在最后一行中断,带有证明状态

1 subgoal
b : binop
e1 : exp
e2 : exp
IHe1 : forall s : stack,
       fold_left instrDenote' (compile e1) (Some s) =
       Some (expDenote e1 :: s)
IHe2 : forall s : stack,
       fold_left instrDenote' (compile e2) (Some s) =
       Some (expDenote e2 :: s)
s : stack
______________________________________(1/1)
fold_left instrDenote' (iBinop b :: nil)
  (fold_left instrDenote' (compile e1) (Some (expDenote e2 :: s))) =
Some (binopDenote b (expDenote e1) (expDenote e2) :: s)
错误是

Error:
Found no subterm matching "fold_left instrDenote' (compile e1)
                             (Some (expDenote e2 :: s))" in the current goal.
在证明的这个阶段,我正在对正在编译的表达式
e
进行归纳,并处理
exp
Binop
构造函数。我不明白为什么会出现这个错误,因为一旦我将
IHe1
应用于
exp表示e2::s
就没有绑定变量了。这似乎是应用重写规则不起作用的常见问题。我还检查了我试图创建的术语:

fold_left instrDenote' (iBinop b :: nil)
  (Some (expDenote e1 :: expDenote e2 :: s)) =
Some (binopDenote b (expDenote e1) (expDenote e2) :: s)
打字检查

当重写规则抱怨的子表达式明显存在于目标中时,重写规则还会出什么问题

编辑:根据建议,我将coqide中的显示设置更改为等同于Set Printing All。这表明问题在于,
stack
的定义在目标中的一个位置被展开为
list nat
,这阻止了子项被识别。使用新设置打印的目标是

1 subgoal
b : binop
e1 : exp
e2 : exp
IHe1 : forall s : stack,
       @eq (option stack)
         (@fold_left (option stack) instr instrDenote' (compile e1)
            (@Some stack s)) (@Some (list nat) (@cons nat (expDenote e1) s))
IHe2 : forall s : stack,
       @eq (option stack)
         (@fold_left (option stack) instr instrDenote' (compile e2)
            (@Some stack s)) (@Some (list nat) (@cons nat (expDenote e2) s))
s : stack
______________________________________(1/1)
@eq (option stack)
  (@fold_left (option stack) instr instrDenote'
     (@cons instr (iBinop b) (@nil instr))
     (@fold_left (option stack) instr instrDenote' (compile e1)
        (@Some (list nat) (@cons nat (expDenote e2) s))))
  (@Some (list nat)
     (@cons nat (binopDenote b (expDenote e1) (expDenote e2)) s))
错误是

Error:
Found no subterm matching "@fold_left (option stack) instr instrDenote'
                             (compile e1)
                             (@Some stack (@cons nat (expDenote e2) s))" in the current goal.

即使使用默认显示设置,子项似乎出现在目标中,启用了“全部打印”,子项显然与目标不匹配,因为在目标中,
堆栈已展开到
列表nat
。因此,需要将
折叠堆栈
转换为目标中的
堆栈

作为一名初学者,我似乎被以下因素绊倒了:

  • 展开
    策略展开的定义比初学者预期的要多

  • 默认的显示设置(在我的例子中是CoqIDE)可以隐藏这一点,因为它们会折叠一些术语


感谢Arthur Azevedo De Amorim建议启用
设置全部打印

如果启用
设置全部打印,您是否可以添加打印的内容。
?(只需在您的证明前添加这一行)完成,谢谢您的建议。现在我看到表达式是不同的,因为
stack
在目标中显示为
list nat
。我对Coq了解不够,无法理解为什么目标中的
stack
的定义会这样扩展(以及为什么它仍然显示为
stack
,带有默认打印设置)。现在我看到了发生的情况,
fold stack
修复了这个问题。从我所读到的内容来看,
展开
策略对于初学者来说并不是很明显的,因为它会将表达式展开到多深的程度,因此与默认的显示设置相结合似乎是问题的原因。