选择subterm进行重写的惯用方法

时间:2017-06-13 08:44:45

标签: coq

假设我们得到了一个形式的结论:a + b + c + d + e 我们还有一个引理:plus_assoc : forall n m p : nat, n + (m + p) = n + m + p

在术语中任意“插入一对圆括号”的惯用方法是什么?也就是说,如果有多个可用位置,我们如何轻松选择重写位置。

我通常最终会做的是:

replace (a + b + c + d + e)
with (a + b + c + (d + e))
by now rewrite <- ?plus_assoc

虽然这个表述确实说明了我想要做的事情, 对于比“a b c ...”更复杂的配方,它变得非常啰嗦。

3 个答案:

答案 0 :(得分:2)

rewrite <- lemma期望lemma是相等的,即类型为something1 = something2的术语。与大多数其他策略一样,您也可以向它传递一个返回相等的函数,即类型为forall param1 … paramN, something1 = something2形式的术语,在这种情况下,Coq将寻找可以应用引理的地方参数形成目标的子项。 Coq的算法是确定性的,但让它选择并不是特别有用,除非在执行最终耗尽所有可能性的重复重写时。在这里,Coq恰好用rewrite <- plus_assoc选择你想要的目标,但我认为这只是一个例子而且你是在一般技术之后。

通过向引理提供更多参数,您可以更好地控制执行重写的位置,以获得更具体的相等性。例如,如果您要指定(((a + b) + c) + d) + e应转换为((a + b) + c) + (d + e),即应将关联性引理应用于参数(a + b) + cd和{{1}你可以写

e

您不需要提供所有参数,只需足以确定您要应用引理的位置。例如,在这里,它足以指定rewrite <- (plus_assoc ((a + b) + c) d e). 作为第二个参数。您可以通过完全保留第三个参数并将通配符d指定为第一个参数来完成此操作。

_

偶尔会有相同的子项,你只想重写其中一个。在这种情况下,您无法单独使用rewrite <- (plus_assoc _ d). 系列战术。一种方法是使用rewrite更大的术语来选择要更改的内容,或使用事件replace来替换整个目标。另一种方法是使用assert策略,它允许您为子项的特定事件命名,然后依靠该名称来标识特定的子项,最后调用set来摆脱在你完成时命名。

另一种方法是忘记要应用哪些引理,并指定您希望如何使用subst或普通assert更改目标。然后,让replace … with ….congruenceomega等自动化策略找到使证明有效的参数。使用这种方法,你必须写下目标的大部分内容,但是你可以节省指定引理。哪种方法最有效取决于您在哪里进行大规模证明,哪些方法在开发过程中趋于稳定,哪些方法不是。

答案 1 :(得分:1)

IMO最好的选择是使用sqreflect模式选择语言,在Coq 8.7中提供,或者在早期版本中安装math-comp。手册中记录了该语言:https://hal.inria.fr/inria-00258384

示例(对于Coq 8.7):

(* Replace with From mathcomp Require ... in Coq < 8.7 *)
From Coq Require Import ssreflect ssrfun ssrbool.

Lemma addnC n m : m + n = n + m. Admitted.
Lemma addnA m n o : m + (n + o) = m + n + o. Admitted.

Lemma example m n o p : n + o + p + m = m + n + o + p.
Proof. by rewrite -[_ + _ + o]addnA -[m + _ + p]addnA [m + _]addnC.
Qed.

答案 2 :(得分:1)

如果你不想证明一个辅助引理,那么你的一个选择就是使用Ltac模式匹配你手上的平等结构。这样,您可以将任意复杂的子表达式绑定到模式变量:

Require Import Coq.Arith.Arith.

Goal forall a b c d e,
    (a + 1 + 2) + b + c + d + e = (a + 1 + 2) + (b + c + d) + e -> True.
  intros a b c d e H.
  match type of H with ?a + ?b + ?c + ?d + ?e = _ =>
    replace (a + b + c + d + e)
       with (a + (b + c + d) + e)
    in H
    by now rewrite <- ?plus_assoc
  end.
Abort.

在上面的代码中?a代表a + 1 + 2。当然,如果您处理简单变量,这不会改进任何内容,只有在处理复杂的嵌套表达式时它才有用。

此外,如果您需要重写目标中的内容,那么您可以使用以下内容:

match goal with
  | |- ?a + ?b + ?c + ?d + ?e = _ => <call your tactics here>