Lean 语言参考

14.8. 定制策略🔗

策略是语法类别 tactic 中的产品。 给定策略的语法,策略解释器负责执行策略单子 TacticM 中的操作,它是 Lean 的术语精化器的包装器,用于跟踪执行所需的附加状态策略。 自定义策略包含 tactic 类别的扩展以及:

  • 将新语法转换为现有语法的 ,或者

  • 执行 TacticM 操作以实现策略的精化器。

14.8.1. 策略宏🔗

定义新策略的最简单方法是将 扩展为已存在的策略。 宏展开与策略交错执行。 策略解释器首先在解释策略宏之前对其进行扩展。 由于策略宏在运行策略脚本之前未完全展开,因此它们可以使用递归;只要宏语法的递归出现位于可执行的策略之下,就不会有无限的扩展链。

Recursive tactic macro

类似于 repeat 的策略的递归实现是通过宏展开定义的。 当参数 $t 失败时,永远不会调用 rep 的递归发生,因此永远不会进行宏扩展。

syntax "rep" tactic : tactic macro_rules | `(tactic|rep $t) => `(tactic| first | $t; rep $t | skip) example : 0 4 := 0 4 rep (Nat.le 0 0) All goals completed! 🐙

与其他 Lean 宏一样,策略宏是 卫生。 对全局名称的引用在定义宏时解析,并且策略宏引入的名称无法从其调用站点捕获名称。

定义策略宏时,指定匹配或构造的语法适用于语法类别 tactic 非常重要。 否则,语法将被解释为术语的语法,这将与策略匹配或构造不正确的 AST。

14.8.1.1. 可扩展策略宏🔗

由于宏展开可能会失败,因此 多个宏可以匹配相同的语法,从而允许回溯。 策略宏更进一步:即使策略宏扩展成功,如果在解释时扩展失败,策略解释器将尝试下一次扩展。 这用于使许多 Lean 的内置策略可扩展 — 可以通过添加 Lean.Parser.Command.macro_rules : commandmacro_rules 声明将新行为添加到策略。

Extending trivial

trivial 被许多其他策略用于快速调度不值得打扰用户的子目标,旨在通过新的宏扩展进行扩展。 Lean 的默认 trivial 无法解决 IsEmpty [] 目标:

def IsEmpty (xs : List α) : Prop := ¬ xs [] example (α : Type u) : IsEmpty (α := α) [] := α:Type uIsEmpty [] Tactic `assumption` failed α:Type uIsEmpty []α:Type uIsEmpty []

该错误消息是 trivial 最后尝试 assumption 的产物。 添加另一个扩展允许 trivial 实现以下目标:

def emptyIsEmpty : IsEmpty (α := α) [] := α:Type u_1IsEmpty [] All goals completed! 🐙 macro_rules | `(tactic|trivial) => `(tactic|exact emptyIsEmpty) example (α : Type u) : IsEmpty (α := α) [] := α:Type uIsEmpty [] All goals completed! 🐙
Expansion Backtracking

当扩展语法的任何部分出现故障时,宏展开可能会导致回溯。 可以通过在单独的 Lean.Parser.Command.macro_rules : commandmacro_rules 声明中提供多个扩展来定义 first 的中缀版本:

syntax tactic "<|||>" tactic : tactic macro_rules | `(tactic|$t1 <|||> $t2) => pure t1 macro_rules | `(tactic|$t1 <|||> $t2) => pure t2 example : 2 = 2 := 2 = 2 All goals completed! 🐙 <|||> apply And.intro example : 2 = 2 := 2 = 2 apply And.intro <|||> All goals completed! 🐙

需要多个 Lean.Parser.Command.macro_rules : commandmacro_rules 声明,因为每个声明都定义一个模式匹配函数,该函数始终采用第一个匹配替代项。 回溯是按 Lean.Parser.Command.macro_rules : commandmacro_rules 声明的粒度进行的,而不是按个别情况进行。