elab_rules : term | `(double($t)) => do let e ← elabTerm t (some (mkConst ``Nat)) mkAppM ``Nat.add #[e, e]
#eval double(21) -- 42
elabTerm 把语法 t elaborate 成 Expr,第二个参数是期望类型(用于类型推断指导)。mkAppM 构造 Nat.add e e。
期望类型的传播
term elaborator 通过第二个隐式参数 expectedType? : Option Expr 接收上下文提供的类型约束:
1 2 3 4 5 6 7 8 9 10 11 12
open Lean Elab Term Meta in elab "typed_zero" : term => do let some expectedType ← getExpectedType? | throwError "typed_zero requires an expected type" -- 检查期望类型是否是 Nat if ← isDefEq expectedType (mkConst ``Nat) then return mkNatLit 0 else throwError "typed_zero only works for Nat"
def x : Nat := typed_zero -- 成功,x = 0 -- def y : Int := typed_zero -- 报错:typed_zero only works for Nat
open Lean Elab Command Meta in elab "#show_type " id:ident : command => do let name ← resolveGlobalConstNoOverload id let env ← getEnv let some info := env.find? name | throwError s!"unknown constant '{name}'" logInfo m!"{name} : {info.type}"
open Lean Elab Command in elab "#check_axioms " ids:ident* : command => do for id in ids do let name ← resolveGlobalConstNoOverload id let env ← getEnv let axioms := Lean.collectAxioms env name if axioms.isEmpty then logInfo m!"{name}: axiom-free" else logWarning m!"{name} depends on: {axioms.toList}"
syntax 与 macro:语法糖层
elab 直接把语法绑定到 elaboration 逻辑。如果只是做语法变换(不需要访问 MetaM),macro 更轻量:
open Lean Elab Command in elab "#count_defs" : command => do let env ← getEnv let mut count := 0 for (_, info) in env.constants.map₁.toList do if info.isDefn then count := count + 1 logInfo m!"Environment contains {count} definitions"
open Lean Elab Command Meta in elab "#add_const " name:ident " := " val:term : command => do let nameN := name.getId let expr ← runTermElabM fun _ => do let e ← Term.elabTerm val none Term.synthesizeSyntheticMVarsNoPostponing let e ← instantiateMVars e return e let type ← runTermElabM fun _ => Meta.inferType expr let decl := Declaration.defnDecl { name := nameN levelParams := [] type := type value := expr hints := .regular 0 safety := .safe } let env ← getEnv match env.addDecl {} decl with | .ok env' => modifyEnv fun _ => env' | .error e => throwError m!"addDecl failed: {e.toMessageData {}}"
open Lean in -- 注册 simp 属性 addSimpTheorem simpExtension name isGlobal attrKind prio
-- 自定义属性的典型模式 initialize myAttr : TagAttribute ← registerTagAttribute `myTag "A custom tag attribute" fun name => do -- 当 @[myTag] 被添加到某个声明时执行的回调 return ()
-- 在 tactic 位置使用 term elaboration example : 1 + 1 = 2 := by show 1 + 1 = 2 -- show 本质上 elaborate 一个 term 作为目标类型 rfl
自定义 term elaborator 中可以创建元变量并让用户用 tactic 填充:
1 2 3 4 5 6
open Lean Elab Term Meta in elab "prove_it " t:term : term => do let type ← elabType t let mvar ← mkFreshExprMVar type -- 这个元变量会变成一个 tactic 目标 return mvar