You can extend Lean with custom tactics/tools; this is metaprogramming.
Combinators help if you have to do the same thing multiple times, or recover from failures.
repeat: applies argument repeatedly on all goals until it can’t be applied any furtheriterate: applies argument repeatedly on first goal until it fails, and then stops<|> (‘orelse’): tries first argument, and if it fails, applies second argumentall_goals: applies argument once to each goal, succeeds only if succeeds on all goalsany_goals: applies argument once to each goal, succeeds if succeeds on any goaltry: transforms argument into tactic that never fails (i.e. try it and if you fail it’s ok)solve1: if argument doesn’t prove the goal, failmeta lets a function call other metafunctions.
Tactics have access to:
tactic.target, tactic.get_goals)tactic.local_context, tactic.get_local ``hypothesis)@[simp] rules)You can print stuff with tactic.trace.
run_cmd can run a tactic.
For example, we can rewrite assumption which looks through all hypotheses in the context and succeeds if it finds one that works with the goal.
meta def exact_list : list expr → tactic unit
| [] := tactic.fail "no matching hypothesis in environment"
| (h :: hs) :=
do { tactic.trace "trying",
tactic.trace h,
tactic.exact h }
<|> exact_list hs
meta def my_assumption : tactic unit :=
do
hs ← tactic.local_context,
exact_list hs
The framework revolves around five main types:
tactic: manages proof state, global context, etcname: represents structured nameexpr: represents expression (term) as abstract syntax tree
expr.var gets variables based on De Bruijn indicesexpr.lam is a lambda expressionexpr.sort are ‘universes’ (Sort 0 is Prop, Sort 1 is Type, etc)expr.local_const is hypothesisexpr.pi is used for pi binders (e.g. ∀)declaration: represents constant declaration, definition, axiom, or lemmaenvironment: stores all declarations and notations that make up global contextUnelaborated expressions (pre-expressions) omit some information, elaborated expressions have everything.
We can create literal expressions:
Similar for names:
Antiquotation lets you embed existing expression into larger expression, using prefix %% and name from current context.
You can also use them in pattern matching, like (%%a + %%b = %%c) ← tactic.target