如何禁止简单策略展开算术表达式?

How to forbid simpl tactic to unfold arithmetic expressions?

simpl 策略将 2 + a 到 "match trees" 这样的表达式展开,这看起来一点也不简单。例如:

Goal forall i:Z, ((fun x => x + i) 3 = i + 3).
simpl.

导致:

forall i : Z,
match i with
| 0 => 3
| Z.pos y' =>
    Z.pos
      match y' with
      | q~1 =>
          match q with
          | q0~1 => (Pos.succ q0)~1
          | q0~0 => (Pos.succ q0)~0
          | 1 => 3
          end~0
      | q~0 =>
          match q with
          | q0~1 => (Pos.succ q0)~0
          | q0~0 => q0~1
          | 1 => 2
          end~1
      | 1 => 4
      end
| Z.neg y' => Z.pos_sub 3 y'
end = i + 3

如何使用simpl策略避免此类并发症?

这个特定的目标可以用 omega 来解决,但如果它更复杂一点,omega 就会失败,我不得不求助于这样的东西:replace (2 + a) with (a + 2); simpl; replace (a + 2) with (2 + a).

您可以使用 TransparentOpaque 命令控制定义展开。在您的示例中,您应该可以说

Opaque Z.add.
simpl.
Transparent Z.add.

或者,Arguments command 可用于指示 simpl 策略以避免在某些上下文中简化术语。例如

Arguments Z.add _ _ : simpl nomatch.

在你的情况下对我有用。这个特殊变体的作用是避免简化一个大的、丑陋的 match 会出现在头部位置的术语(你在你的例子中看到的)。但是,还有其他变体。

最后,为了完整起见,Ssreflect 库提供了很好的基础设施,使某些定义在本地不透明。所以你可以这样说

rewrite (lock Z.add) /= -lock.

意思是"lock Z.add, so that it won't simplify, then simplify the remaining of the expression (the /= switch), then unlock the definition again (-lock)"。

您可以调整简单策略的行为方式,从而减少匹配次数。

Require Import Coq.ZArith.ZArith.

Goal forall i:Z, ((fun x => (x + i)%Z) 3%Z = (i + 3)%Z).
Arguments Z.add x y : simpl nomatch.
simpl.

了解更多信息 here

否则您可以使用 other tactics 来选择如何减少。 cbn beta,例如