Zulip Chat Archive

Stream: lean4

Topic: RFC: a trace variant of the tactic `trivial`, aka `trivial?`


Yongshun Ye (Jul 29 2025 at 09:35):

It's a common topic that something in math can be trivial for one person but not for another. Especially for beginners, understanding why/how something is trivial is important. Lean's trivial tactic delegates to 6 other tactics as I see from the source code. So I think it would make Lean more friendly especially to new users by adding a trace variant trivial?, which suggests the underlying tactic used, just like simp?, apply?, etc. If OK, I am happy take on the implementation of this and submit a PR.

Robin Arnez (Jul 29 2025 at 11:27):

Actually, why not expand all macros?

import Lean

def cleanMacroScopes (stx : Lean.Syntax) : Lean.Syntax :=
  match stx with
  | .ident info raw val pre => .ident info raw val.eraseMacroScopes pre
  | .node info kind args =>
    if kind = ``Lean.Parser.Tactic.withAnnotateState then
      if h : args.size > 2 then
        cleanMacroScopes args[2]
      else
        stx
    else
      .node info kind (args.map cleanMacroScopes)
  | stx => stx

def null : Lean.Parser.Parser := Lean.Parser.many Lean.Parser.commandParser

open Lean Syntax MonadTraverser Parser PrettyPrinter Formatter in
@[formatter null]
def null.formatter : Lean.PrettyPrinter.Formatter := do
  let stx  getCur
  ppDedent.formatter do
    visitArgs $ stx.getArgs.size.forM fun i _ => do
      if i > 0 then
        ppLine.formatter
        ppLine.formatter
      commandParser.formatter

open Lean Parser PrettyPrinter Parenthesizer in
@[parenthesizer null]
def null.parenthesizer : Lean.PrettyPrinter.Parenthesizer :=
  many.parenthesizer commandParser.parenthesizer

open Lean Meta Elab Tactic in
partial def addMacroExpandSuggestions (tree : InfoTree) (ctx : ContextInfo) : MetaM Unit := do
  match tree with
  | .context pctx tree =>
    addMacroExpandSuggestions tree ((pctx.mergeIntoOuter? (some ctx)).getD ctx)
  | .hole _ => pure ()
  | .node info children =>
    match info with
    | .ofTacticInfo tac =>
      let elabName := tac.elaborator
      let some _ := info.range? |
        children.forM (addMacroExpandSuggestions · ctx)
      let some elabDecl := ctx.env.findConstVal? elabName |
        children.forM (addMacroExpandSuggestions · ctx)
      if elabDecl.type.isConstOf ``Macro then
        if h : children.size = 1 then
          let inner := children[0]
          if let .node innerInfo _ := inner then
            TryThis.addSuggestion tac.stx (cleanMacroScopes innerInfo.stx : Syntax.Tactic)
            return
      children.forM (addMacroExpandSuggestions · ctx)
    | .ofMacroExpansionInfo mac =>
      if mac.stx.isOfKind ``Parser.Term.paren then
        children.forM (addMacroExpandSuggestions · ctx)
      else
        let some _ := info.range? | children.forM (addMacroExpandSuggestions · ctx)
        TryThis.addSuggestion mac.stx (cleanMacroScopes mac.output : Syntax.Term)
    | _ => children.forM (addMacroExpandSuggestions · ctx)

open Lean Elab Term in
def getContextInfo : TermElabM ContextInfo :=
  return {
    env :=  getEnv
    fileMap :=  getFileMap
    ngen :=  getNGen
    openDecls :=  getOpenDecls
    mctx :=  getMCtx
    options :=  getOptions
    currNamespace :=  getCurrNamespace
    parentDecl? :=  Term.getDeclName?
  }

open Lean Meta Elab Tactic in
elab "macro_expand?" s:tacticSeq : tactic => do
  evalTacticSeq s
  let trees := ( getInfoState).substituteLazy.get.trees
  let context : ContextInfo  getContextInfo
  for tree in trees do
    addMacroExpandSuggestions tree context

open Lean Meta Elab Term in
elab "macro_expand% " stx:term : term => do
  let expr  elabTerm stx ‹_›
  let trees := ( getInfoState).substituteLazy.get.trees
  let context : ContextInfo  getContextInfo
  for tree in trees do
    addMacroExpandSuggestions tree context
  return expr

open Lean Meta Elab Command in
elab "#macro_expand " "in " stx:command : command => do
  let expr  elabCommand stx
  let trees := ( getInfoState).substituteLazy.get.trees
  liftTermElabM <| do
    let context : ContextInfo  getContextInfo
    for tree in trees do
      addMacroExpandSuggestions tree context
    return expr

Robin Arnez (Jul 29 2025 at 11:35):

This is quite fun to play around with (just put #macro_expand in above your command of choice)

Kyle Miller (Jul 29 2025 at 12:17):

@Yongshun Shreck Ye If you "go to definition" on a use of trivial, it should go to the macro rule that applied.

Yongshun Ye (Jul 29 2025 at 12:43):

@Kyle Miller Thanks. It's good to know.

Yongshun Ye (Jul 29 2025 at 13:02):

@Robin Arnez Yeah this does look like a more general and well-rounded approach.


Last updated: Dec 20 2025 at 21:32 UTC