如何在不评估函数本身的情况下有选择地简化每次调用函数时的参数?

时间:2016-12-31 00:23:26

标签: coq coq-tactic

我使用的是Coq 8.5pl1。

制作一个人为的但是说明性的例子,

(* fix so simpl will automatically unfold. *)
Definition double := fix f n := 2*n.

Theorem contrived n : double (2 + n) = 2 + double (1 + n).

现在,我只想将参数简化为double, 而不是它之外的任何部分。 (例如,因为 休息时已经仔细考虑了。)

simpl.
   S (S (n + S (S (n + 0)))) = S (S (S (n + S (n + 0))))

这将外部(2 + ...)转换为(S(S ...))以及展开双倍。

我可以通过以下方式匹配其中一个:

match goal with | |- (double ?A) = _ => simpl A end.
   double (S (S n)) = 2 + double (1 + n)

我怎么说我想简化所有这些? 也就是说,我想得到

   double (S (S n)) = 2 + double (S n)

无需为每次调用添加单独的模式。

我可以用

来简化双倍本身
remember double as x; simpl; subst x.
   double (S (S n)) = S (S (double (S n)))

2 个答案:

答案 0 :(得分:4)

不透明/透明方法

结合this answerthis one的结果,我们得到以下解决方案:

Opaque double.
simpl (double _).
Transparent double.

我们使用simpl的模式功能缩小其行动域"和Opaque / Transparent以禁止(允许等)展开{ {1}}。

自定义策略方法

我们还可以定义一个简化参数的自定义策略:

double

需要(* simplifies the first argument of a function *) Ltac simpl_arg_of function := repeat multimatch goal with | |- context [function ?A] => let A' := eval cbn -[function] in A in change A with A' end. 构造来保护嵌套函数不被简化。这是一个简单的测试:

let A' := ...

以上结果

Fact test n :
    82 + double (2 + n)
  =
    double (1 + double (1 + 20)) + double (1 * n).
Proof.
  simpl_arg_of double.

如果我们在82 + double (S (S n)) = double (S (double 21)) + double (n + 0) 的定义中使用context [function ?A] => simpl A这样的内容,我们就会得到

simpl_arg_of

代替。

参数指令方法

正如@eponier在评论中所建议的,我们可以利用另一种形式的82 + double (S (S n)) = double 43 + double (n + 0) - simpl,手册(sect. 8.7.4)定义为:

  

这仅将simpl <qualid>应用于头部出现为可展开常量 qualid 的应用子项(如果存在这样的符号,则可以使用字符串通过其符号来引用该常量)。 / p>

simpl / Opaque方法无法使用,但我们可以使用Transparent指令阻止展开double

Arguments

答案 1 :(得分:2)

您可能会发现ssreflect模式选择语言和重写机制在这里很有用。例如,您可以使用模式+简单运算符/=

进行更细粒度的控制
From mathcomp Require Import ssreflect.
Definition double := fix f n := 2*n.
Theorem contrived n : double (2 + n) = 2 + double (1 + n).
rewrite ![_+n]/=.

将显示:

n : nat
============================
double (S (S n)) = 2 + double (S n)

您还可以使用匿名重写规则:

rewrite (_ : double (2+n) = 2 + double (1+n)) //.

我个人认为重写在较小的引理中:

Lemma doubleE n : double n = n + n.
Proof. by elim: n => //= n ihn; rewrite -!plus_n_Sm -plus_n_O. Qed.

Lemma doubleS n : double (1 + n) = 2 + double n.
Proof. by rewrite !doubleE /= -plus_n_Sm. Qed.

Theorem contrived n : double (1+n) = 2 + double n.
rewrite doubleS.