Theorem Proving in Lean 4

11. 转换策略模式🔗

在策略块(tactic block)内,可以使用关键字 conv 进入 转换模式(conversion mode)。该模式允许在假设和 目标内部进行导航,即使在函数抽象和依值箭头内部, 也可以应用重写或化简步骤。

11.1. 基本导航与重写🔗

作为第一个例子,让我们证明示例 (a b c : Nat) : a * (b * c) = a * (c * b) (此文件中的示例有些人为设计,因为 其他策略可以立即完成它们)。最直接 的首次尝试是进入策略模式并尝试 rw [Nat.mul_comm]。但这会将目标变换为 b * c * a = a * (c * b),在交换了项中出现的 第一个乘法之后。有多种 方法可以解决此问题,其中一种方法是使用更精确的工具: 转换模式。以下代码块显示了每一行之后的当前目标。

#guard_msgs (drop all) in example (a b c : Nat) : a * (b * c) = a * (c * b) := a:Natb:Natc:Nata * (b * c) = a * (c * b) a:Natb:Natc:Natb * c * a = a * (c * b) example (a b c : Nat) : a * (b * c) = a * (c * b) := a:Natb:Natc:Nata * (b * c) = a * (c * b) a:Natb:Natc:Nat| a * (b * c) = a * (c * b) a:Natb:Natc:Nat| a * (b * c) a:Natb:Natc:Nat| aa:Natb:Natc:Nat| b * c a:Natb:Natc:Nat| b * c a:Natb:Natc:Nat| c * b

以上代码片段展示了三个导航命令:

  • lhs 导航到关系(此处为等式)的左侧。 还有 rhs 用于导航到右侧。

  • congr 为当前头部函数创建与(非依值和显式)参数数量相同的目标 (此处头部函数是乘法)。

  • rfl 使用自反性(reflexivity)关闭目标。

一旦到达相关目标,我们可以像在普通策略模式中一样使用 rw

使用转换模式的第二个主要原因是重写绑定器(binder)内部。假设我们想要证明示例 (fun x : Nat => 0 + x) = (fun x => x)。 最直接的首次尝试是进入策略模式并尝试 rw [Nat.zero_add]。但这会失败,并出现令人沮丧的

error: tactic 'rewrite' failed, did not find instance of the pattern
       in the target expression
  0 + ?n
⊢ (fun x => 0 + x) = fun x => x

解决方案是:

example : (fun x : Nat => 0 + x) = (fun x => x) := (fun x => 0 + x) = fun x => x | (fun x => 0 + x) = fun x => x | fun x => 0 + x x:Nat| 0 + x x:Nat| x

其中 intro x 是进入 fun 绑定器内部的导航命令。 请注意,此示例有些人为设计,我们也可以这样做:

example : (fun x : Nat => 0 + x) = (fun x => x) := (fun x => 0 + x) = fun x => x x:Nat0 + x = x; All goals completed! 🐙

或者简单地

example : (fun x : Nat => 0 + x) = (fun x => x) := (fun x => 0 + x) = fun x => x All goals completed! 🐙

conv 也可以使用 conv at h 重写来自局部上下文(local context)的假设(hypothesis)h

11.2. 模式匹配🔗

使用上述命令进行导航可能很繁琐。可以通过模式匹配来简化,如下所示:

example (a b c : Nat) : a * (b * c) = a * (c * b) := a:Natb:Natc:Nata * (b * c) = a * (c * b) a:Natb:Natc:Nat| b * c a:Natb:Natc:Nat| c * b

这只是以下内容的语法糖

example (a b c : Nat) : a * (b * c) = a * (c * b) := a:Natb:Natc:Nata * (b * c) = a * (c * b) a:Natb:Natc:Nat| a * (b * c) = a * (c * b) a:Natb:Natc:Nat| b * c a:Natb:Natc:Nat| c * b

当然,允许使用通配符(wildcard):

example (a b c : Nat) : a * (b * c) = a * (c * b) := a:Natb:Natc:Nata * (b * c) = a * (c * b) a:Natb:Natc:Nat| b * c a:Natb:Natc:Nat| c * b

11.3. 结构化转换策略🔗

花括号(curly bracket)和 . 也可以在 conv 模式中用于结构化策略:

example (a b c : Nat) : (0 + a) * (b * c) = a * (c * b) := a:Natb:Natc:Nat(0 + a) * (b * c) = a * (c * b) a:Natb:Natc:Nat| (0 + a) * (b * c) = a * (c * b) a:Natb:Natc:Nat| (0 + a) * (b * c) a:Natb:Natc:Nat| 0 + aa:Natb:Natc:Nat| b * c . a:Natb:Natc:Nat| a . a:Natb:Natc:Nat| c * b

11.4. 转换模式中的其他策略🔗

  • arg i 进入某个应用的第 i 个非依值显式参数。

    example (a b c : Nat) : a * (b * c) = a * (c * b) := a:Natb:Natc:Nata * (b * c) = a * (c * b) a:Natb:Natc:Nat| a * (b * c) = a * (c * b) a:Natb:Natc:Nat| a * (b * c) a:Natb:Natc:Nat| b * c a:Natb:Natc:Nat| c * b
  • argscongr 的替代名称。

  • simp 将化简器(simplifier)应用于当前目标。它支持与普通策略模式中相同的选项。

    def f (x : Nat) := if x > 0 then x + 1 else x + 2 example (g : Nat Nat) (h₁ : g x = x + 1) (h₂ : x > 0) : g x = f x := x:Natg:Nat Nath₁:g x = x + 1h₂:x > 0g x = f x x:Natg:Nat Nath₁:g x = x + 1h₂:x > 0| g x = f x x:Natg:Nat Nath₁:g x = x + 1h₂:x > 0| f x x:Natg:Nat Nath₁:g x = x + 1h₂:x > 0| x + 1 All goals completed! 🐙
  • enter [1, x, 2, y] 使用给定的参数迭代 argintro

  • done 在存在未解决的目标时失败。

  • trace_state 显示当前策略状态。

  • whnf 将项置于弱头正规形式(weak head normal form)。

  • tactic => <tactic sequence> 返回常规策略模式。这 对于处理 conv 模式不支持的目标,以及 应用自定义的同余(congruence)和外延性(extensionality)引理非常有用。

    example (g : Nat Nat Nat) (h₁ : x, x 0 g x x = 1) (h₂ : x 0) : g x x + x = 1 + x := x:Natg:Nat Nat Nath₁: (x : Nat), x 0 g x x = 1h₂:x 0g x x + x = 1 + x x:Natg:Nat Nat Nath₁: (x : Nat), x 0 g x x = 1h₂:x 0| g x x + x = 1 + x x:Natg:Nat Nat Nath₁: (x : Nat), x 0 g x x = 1h₂:x 0| g x x + x x:Natg:Nat Nat Nath₁: (x : Nat), x 0 g x x = 1h₂:x 0| g x x x:Natg:Nat Nat Nath₁: (x : Nat), x 0 g x x = 1h₂:x 0| 1x:Natg:Nat Nat Nath₁: (x : Nat), x 0 g x x = 1h₂:x 0x 0 . x:Natg:Nat Nat Nath₁: (x : Nat), x 0 g x x = 1h₂:x 0| 1 . x:Natg:Nat Nat Nath₁: (x : Nat), x 0 g x x = 1h₂:x 0x 0 All goals completed! 🐙
  • apply <term>tactic => apply <term> 的语法糖。

    example (g : Nat Nat Nat) (h₁ : x, x 0 g x x = 1) (h₂ : x 0) : g x x + x = 1 + x := x:Natg:Nat Nat Nath₁: (x : Nat), x 0 g x x = 1h₂:x 0g x x + x = 1 + x x:Natg:Nat Nat Nath₁: (x : Nat), x 0 g x x = 1h₂:x 0| g x x + x = 1 + x x:Natg:Nat Nat Nath₁: (x : Nat), x 0 g x x = 1h₂:x 0| g x x + x x:Natg:Nat Nat Nath₁: (x : Nat), x 0 g x x = 1h₂:x 0| g x x x:Natg:Nat Nat Nath₁: (x : Nat), x 0 g x x = 1h₂:x 0| 1x:Natg:Nat Nat Nath₁: (x : Nat), x 0 g x x = 1h₂:x 0x 0 . x:Natg:Nat Nat Nath₁: (x : Nat), x 0 g x x = 1h₂:x 0| 1 . All goals completed! 🐙