为什么我有时可以通过引理证明一个目标,但不是直接?

时间:2015-06-06 13:20:37

标签: coq

考虑下面定义的功能。它的作用并不重要。

Require Import Ring.
Require Import Vector.
Require Import ArithRing.

Fixpoint
  ScatHUnion_0 {A} (n:nat) (pad:nat) : t A n -> t (option A) ((S pad) * n).
 refine (
  match n return (t A n) -> (t (option A) ((S pad)*n)) with
  | 0 => fun _ =>  (fun H => _)(@nil (option A))
  | S p =>
    fun a =>
      let foo := (@ScatHUnion_0 A p pad (tl a)) in
      (fun H => _) (cons _ (Some (hd a)) _ (append (const None pad) foo))
  end
   ).
 rewrite  <-(mult_n_O (S pad)); auto.
 replace  (S pad * S p) with ( (S (pad + S pad * p)) ); auto; ring.
Defined.

我想证明

Lemma test0:  @ScatHUnion_0 nat 0 0 ( @nil nat) = ( @nil (option nat)).

完成后

  simpl. unfold eq_rect_r. unfold eq_rect.

目标是

         match mult_n_O 1 in (_ = y) return (t (option nat) y) with
         | eq_refl => nil (option nat)
         end = nil (option nat)

尝试用

完成时
  apply trans_eq with (Vector.const (@None nat) (1 * 0)); auto.
  destruct (mult_n_O 1); auto.

destruct不起作用(请参阅下面的错误消息)。但是,如果我首先在引理中证明了完全相同的目标,或者甚至在证明中使用assert,我可以应用并解决它,如下所示:

Lemma test1:  @ScatHUnion_0 nat 0 0 ( @nil nat) = ( @nil (option nat)).
  simpl. unfold eq_rect_r. unfold eq_rect.

  assert (
      match mult_n_O 1 in (_ = y) return (t (option nat) y) with
        | eq_refl => nil (option nat)
      end = nil (option nat)
    ) as H.
  {
    apply trans_eq with (Vector.const (@None nat) (1 * 0)); auto.
    destruct (mult_n_O 1); auto.
  }
    apply H.
Qed.

有人可以解释为什么会这样,以及在遇到这种情况时应该如何考虑这种情况?

在Coq 8.4中我收到错误

      Toplevel input, characters 0-21:
      Error: Abstracting over the terms "n" and "e" leads to a term
      "fun (n : nat) (e : 0 = n) =>
       match e in (_ = y) return (t (option nat) y) with
       | eq_refl => nil (option nat)
       end = const None n" which is ill-typed.

在Coq 8.5中我得到了错误

      Error: Abstracting over the terms "n" and "e" leads to a term
      fun (n0 : nat) (e0 : 0 = n0) =>
      match e0 in (_ = y) return (t (option nat) y) with
      | eq_refl => nil (option nat)
      end = const None n0
      which is ill-typed.
      Reason is: Illegal application: 
      The term "@eq" of type "forall A : Type, A -> A -> Prop"
      cannot be applied to the terms
       "t (option nat) 0" : "Set"
       "match e0 in (_ = y) return (t (option nat) y) with
        | eq_refl => nil (option nat)
        end" : "t (option nat) n0"
       "const None n0" : "t (option nat) n0"
      The 2nd term has type "t (option nat) n0" which should be coercible to
       "t (option nat) 0".

2 个答案:

答案 0 :(得分:2)

@Vinz回答解释了原因,并建议Set Printing All.显示了区别。问题是simpl.简化了match的返回类型。使用unfold ScatHUnion_0.代替simpl.,我可以直接在目标上使用destruct。

从根本上说,我的麻烦源于我想要说服类型系统0=00=1*0相同。 (顺便说一句,我仍然不知道最好的方法。)我使用mult_n_O来表示,但它是不透明的,所以类型系统在检查时不能展开它这两种类型是平等的。

当我用我自己的Fixpoint变体(不是不透明的)替换它时,

Fixpoint mult_n_O n: 0 = n*0 :=
    match n as n0 return (0 = n0 * 0) with
  | 0 => eq_refl
  | S n' => mult_n_O n'
  end.

并在ScatHUnion_0的定义中使用它,引理很容易证明:

Lemma test0:  @ScatHUnion_0 nat 0 0 ( @nil nat) = ( @nil (option nat)).
  reflexivity.
Qed.

补充评论:

这是一个适用于原始不透明mult_n_O定义的证明。它基于proof by Jason Gross。 它使用mult_n_O 10=0的类型设为generalize。它使用set来修改术语的隐式部分,例如eq_refl中的类型,该类型仅在Set Printing All.命令后可见。 change也可以这样做,但replacerewrite似乎无法做到这一点。

Lemma test02:
  match mult_n_O 1 in (_ = y) return (t (option nat) y) with
    | eq_refl => nil (option nat)
  end = nil (option nat).
Proof.
  Set Printing All.
  generalize (mult_n_O 1 : 0=0).
  simpl.
  set (z:=0) at 2 3.
  change (nil (option nat)) with (const (@None nat) z) at 2.
  destruct e.
  reflexivity.
Qed.

更新:感谢coq-club的人们,这是一个更简单的证据。

Lemma test03:
  match mult_n_O 1 in (_ = y) return (t (option nat) y) with
    | eq_refl => nil (option nat)
  end = nil (option nat).
Proof.
  replace (mult_n_O 1) with (@eq_refl nat 0);
  auto using Peano_dec.UIP_nat.
Qed.

答案 1 :(得分:1)

我会说这是因为依赖类型,并且在两种情况下你都没有真正证明完全相同的东西(尝试Set Printing All.来看隐式类型和隐藏信息)。

这种破坏失败的事实通常是因为依赖会引入一个不合适的术语,你必须更精确地指出你想破坏的东西(这里不是秘密,它是一个案例基础)。通过提取子引理,您可能已经删除了麻烦的依赖关系,现在破坏可以运行。