Zulip Chat Archive

Stream: lean4

Topic: refer to unnamed (hygienic) section variables in notations


George Pîrlea (Nov 07 2024 at 14:35):

I have a DSL where I define some section variables behind the user's back, so to speak, and I want to define notations to hide these away, but I can't figure out how to do it. Here's a MWE:

import Lean
open Lean Parser Elab Command

set_option quotPrecheck false

def toFnName (id : Ident) : Ident :=
  mkIdent (id.getId ++ `fn)

elab "function" nm:ident br:(bracketedBinder)* "=" dfn:term : command => do
  elabCommand $  runTermElabM fun _ => do
    `(command|def $(toFnName nm) $br* := $dfn)
  elabCommand $  runTermElabM fun vs => do
    let args  vs.mapM (fun v => do
    let t  PrettyPrinter.delab v ; dbg_trace "{t}" ; return t)
    let strName  `(Lean.Parser.Command.notationItem|$(Lean.quote nm.getId.toString):str)
    `(local notation (priority := default) $strName => @$(toFnName nm) $args*)

variable (t : Type) [DecidableEq t]

set_option trace.Elab.command true
-- defines `local notation (priority := default) "foo" => @foo.fn t inst✝`
-- ... which throws an error when applied because `inst✝` is not a valid name
function foo (x : t) = (x = x)
#check foo.fn -- OK
#check foo    -- unknown identifier 'inst✝'

How can I refer to inst✝ (the DecidableEq instance) when I define the notation? Or maybe figure out when there is a hygienic name and try to synthesise the appropriate instance (but this might not always work)?

Perhaps there's a better solution to my problem than notations?

Any help is appreciated.

George Pîrlea (Nov 08 2024 at 10:12):

This is a work-around, but I can imagine this not always working:

let args  vs.mapM (fun v => do
  let t  PrettyPrinter.delab v
  let isHygienicName := (extractMacroScopes t.raw.getId).scopes.length > 0
  if isHygienicName then return  `(term|_) else return t
)

Last updated: May 02 2025 at 03:31 UTC