-
Notifications
You must be signed in to change notification settings - Fork 438
Metaprogramming for dummies
This is an overview to the most common functions that are useful for writing tactics in Lean 4. We assume some knowledge of functional programming and a basic understanding of how metaprogramming works in Lean 4. The standard references are Lean 4 Metaprogramming book and Functional Programming in Lean, respectively.
-
MetaM is the monad you want to use if you modify metavariables.
-
TacticM is the topmost monad for tactic-writing. You can get and set goals, etc
In a do
block (←) takes care of bumping to a stronger monad
- mapM
- (←)
- filterM
- elabTerm
- elabTermForApply
- elabTermEnsuringType
withLocalDeclD
open Lean.Expr
Check whether something is a metavariable: Create metavariable: Assign metavariable: Check whether it is assigned
Note about delayed assignments (and reference to meta-book)
isBVar
isLambda lambdaTelescope
isForall forallTelescope
- isApp
- getAppFn
- getAppNumArgs
- getAppArgs
-
Expr.getAppFnArgs
: This is useful if you have an expression and you want to pattern-match
open Lean.Elab.Tactic
getGoals getMainGoal setGoals
open Lean.Elab.Tactic
evalTactic withMainContext liftMetaTactic
Lean.MVarId.apply
Example:
If no universe levels: mvarId.apply (mkConst foo []) If known universe levels: mvarId.apply (mkConst
foo [u,v])
Otherwise: mvarId.apply (← mkConstWithFreshMVarLevels ``foo)
However, see also: Qq
.
- The easy stuff
- Qq (Qq is love, Qq is life).
If you want to build expressions, it's a good idea to use Qq
instead of manually building them from the constructors. The Q(α)
macro is a synonym of Expr
, with the (unchecked?) assertion that any e : Q(α)
typechecks to have type α
. And you can build elements of Q
using q
, and it will automatically, statically, fill in implicits. Instances are looked up in the context of the q
invocation.
Unfortunately, errors generated by Qq
are hard to understand.
-
dbg_trace s!"foo {var}"
is the most lowlevel way of debugging anything -
logInfo s!"foo {var}"
is slightly more sophisticated and only works in monads that support logging (in particular inMetaM
andTacticM
) -
trace[identifier] s!"foo {var}"
is the serious way of logging output. To declare a trace class invokeinitialize registerTraceClass identifier
and then activate the logging withset_option trace.identifier true
. Note that the logging does not work in the file where the trace class is defined.