Coq 类型类解析和自动重写

Coq 类型类解析和自动重写,coq,Coq,我有一个重写引理的基础。其中一些由类型类参数化。当应用引理时,当Coq不能自动解析typeclass时,重写失败是很重要的。我发现获得这种行为的唯一方法是声明大多数隐式参数 Class T (t:Type) : Type. Instance T1 : T nat. Instance T2 : forall {A1 A2:Type} {t1:T A1} {t2:T A2}, T (A1*A2). Definition f {A:Type} (x:A) := x. Lemma f_eq : fo

我有一个重写引理的基础。其中一些由类型类参数化。当应用引理时,当Coq不能自动解析typeclass时,重写失败是很重要的。我发现获得这种行为的唯一方法是声明大多数隐式参数

Class T (t:Type) : Type.
Instance T1 : T nat.
Instance T2 : forall {A1 A2:Type} {t1:T A1} {t2:T A2}, T (A1*A2).

Definition f {A:Type} (x:A) := x.

Lemma f_eq : forall {A:Type} (t:T A) (x:A), f x = x.
Proof.
  reflexivity.
Qed.

Lemma test1 : f (0,1) = (0,1).
Proof.
  rewrite f_eq.
  (* a subgoal T (nat * nat) is generated,
     which should have been resolved directly *)
Abort.

Lemma test2 : f (0,true) = (0,true).
Proof.
  rewrite f_eq.
  (* a subgoal T (nat * bool) is generated,
     while it should have failed *)
Abort.

Arguments f_eq {_ _} _.

Lemma test1 : f (0,1) = (0,1).
Proof.
  rewrite f_eq.
  reflexivity. (* OK *)
Qed.

Lemma test2 : f (0,true) = (0,true).
Proof.
  Fail rewrite f_eq. (* fails as expected *)
Abort.
然后我想把引理添加到重写数据库中,但是添加到数据库中的引理已经是专门化的了

Hint Rewrite f_eq : my_db. Print Rewrite HintDb my_db. (* Database my_db rewrite -> f_eq of type forall x : nat, f x = x *) 提示重写f_eq:my_db。 打印重写HintDb my_db。 (*数据库我的数据库) 重写->所有x类型的f_等式:nat,f x=x*) 如何将引理添加到重写数据库中,并在其参数的类型类解析方面获得正确的行为

编辑:有一个选项
在应用后设置Typeclass分辨率。
似乎启用了我期望的行为,但仅适用于
应用
,而不是
重写
。 相应的提交给出了以下描述:

添加一个选项以解决由apply生成的类型类目标,该选项不能 由于evars和metas之间的差异,否则会被捕获


一种可能的解决方案是使用ssreflect的重写(这将解决问题的第一部分),并用多重重写规则替换提示数据库。也就是说:

From mathcomp Require Import ssreflect.

Class T (t:Type) : Type.
Instance T1 : T nat.
Instance T2 : forall {A1 A2:Type} {t1:T A1} {t2:T A2}, T (A1*A2).

Definition f {A:Type} (x:A) := x.

Lemma f_eq : forall {A:Type} (t : T A) (x:A), f x = x.
Proof. by []. Qed.

(* Add more lemmas as needed *)
Definition my_db A := (@f_eq A, @f_eq A).

Lemma test1 : f (0,1) = (0,1).
Proof. by rewrite my_db. Qed.

Lemma test2 : f (0,true) = (0,true).
Proof.
Fail rewrite f_eq.
Abort.

这里有一个解决办法。首先,我们添加了广义引理,但我们告诉
autorewrite
策略使用策略
exact
来解决解决必要的typeclass实例的次要目标

Hint Rewrite @f_eq using (exact _): my_db.
Print Rewrite HintDb my_db.
(*
  Database my_db
  rewrite -> @f_eq of type forall A : Type, T A -> forall x : A, f x = x
  then use tactic exact _
*)
然后,您可以继续使用
rewrite
进行重写,如您在问题正文中所示,也可以使用您的数据库:

Lemma test1' : f (0,1) = (0,1).
Proof.
  autorewrite with my_db.
  reflexivity.
Qed.

Lemma test2 : f (0,true) = (0,true).
Proof.
  autorewrite with my_db.
  (* does nothing: no rewrites, no error messages *)
Abort.
请注意,在最后一种情况下,当我们使用
exact
Coq时,它不会生成表单
Build_T(nat*bool)
的新实例,如果我们使用
自反性
。 这里有一个例子来说明我的意思。如果我们从这个提示开始

Hint Rewrite @f_eq using reflexivity: my_db.
我们可以用这种方式证明test2

Lemma test2 : f (0,true) = (0,true).
Proof.
  autorewrite with my_db.
  reflexivity.
Qed.
但是如果我们使用
设置打印所有。打印测试2。
我们将看到Coq构建了一个新的
T
(Build_T(prod nat bool))
实例,我认为这与您的目标背道而驰——似乎您更希望Coq推断出一个已经存在的
T
实例,如果它有可能或者以某种方式失败

我们可以手动重复相同的操作:

Lemma test2' : f (0,true) = (0,true).
Proof.
  rewrite @f_eq. reflexivity.
  exact (Build_T (nat * bool)). (* `exact _` won't work *)
Qed.

第二次重写的错误信息给我留下了深刻的印象(
error:f_eq(f_)的LHS匹配,但类型类推理失败
),它不能更清晰,但我更喜欢没有ssreflect的解决方案。我不理解的是,标准重写和ssreflect重写在类型类分辨率处理上的区别。正如我在文章中所解释的,当使用带有标准重写的TypeClass时,我总是需要利用参数的隐含性来强制解析。对于ssreflect的重写,它似乎总是有效的。@eponier AFAICT有不同的策略和工作方式。这很有趣。我最好的尝试是
使用typeclasses eauto:My_db.
提示重写f_eq,但我认为这应该可以直接工作。关于
自反性
,我不明白它为什么起作用,它的作用是什么。@eponier我已经试着解释了我关于
自反性
的意思。谢谢,这更清楚了。实际上,我忘记了TypeClass基本上是记录,没有任何字段的记录可以很容易地实例化。事实上,在这种情况下我希望避免这种情况。我不确定这是否正确,但似乎
apply
使用了现有的typeclass实例,而不是重建它们。因此,
Hint用apply重写f_eq:my_db
可能会做你想做的事。FWIW,如果你用这个
Definition f{A:Type}{t:ta}(x:A):=x.
,你就可以使用重写提示,你甚至不能声明
引理test2:f(0,true)=(0,true)。