Zulip Chat Archive

Stream: lean4

Topic: root namespace with idents


Adam Topaz (Oct 06 2022 at 22:29):

Consider the following code snippet:

import Lean
open Lean


macro "foo" s:str : command => do
  let i : Ident := mkIdent (.str .anonymous s.getString)
  `(def $i := (1 : Nat))

macro "bar" s:str : command => do
  let i : Ident := mkIdent ("_root_" ++ s.getString)
  `(def $i := (1 : Nat))

namespace blah

foo "test"
bar "baz"

end blah

#check blah.test
#check baz

This works. What I'm wondering about is how to accomplish the behavior of "bar" similarly to "foo" (i.e. without resorting to manipulating strings with "_root_"). Any pointers?

Gabriel Ebner (Oct 06 2022 at 23:20):

Are you looking for `_root_ ++ s.getString or .str (.str .anonymous "_root_") s.getString?

Adam Topaz (Oct 07 2022 at 00:46):

I'm not sure what I'm looking for. I guess at the end of the day I'm wondering if there is a way to get to the root namespace without using "_root_" (or `_root_)

Mario Carneiro (Oct 07 2022 at 00:47):

not if you are constrained to generate an identifier that goes into def

Mario Carneiro (Oct 07 2022 at 00:47):

you could just call the underlying API, in which case you can name it whatever you want

Adam Topaz (Oct 07 2022 at 00:51):

Fair enough. Thanks. Where can I find the underlying API for making defs, structures, etc.?

Mario Carneiro (Oct 07 2022 at 00:56):

I usually just follow the trail starting at the syntax, to src4#Lean.Elab.Command.elabDeclaration, to src4#Lean.Elab.addPreDefinitions, and finally to src4#Lean.addDecl, depending on how much of the def stuff you want to do

Mario Carneiro (Oct 07 2022 at 00:57):

addDecl is the kernel interface; in particular it doesn't compile the definition (you need src4#Lean.addAndCompile for that)

Adam Topaz (Oct 07 2022 at 01:00):

Sorry... I'm a bit slow. What should I do to "follow the trail"?

Adam Topaz (Oct 07 2022 at 01:03):

My first instinct would be to do something like

#check (`(def a : Nat := 0) : MacroM _)

but I don't see any of the functions you mentioned by doing this.

Mario Carneiro (Oct 07 2022 at 01:11):

Let's say we want to know what def does.

  • My first step is to search the codebase for "def, "def or "def", which usually takes me to the declaration of the syntax, in this case src4#Lean.Parser.Command.def
  • This isn't actually a command parser (you can tell because it doesn't have a@[builtinCommandParser] attribute), but if you look for uses in the same file you find src4#Lean.Parser.Command.declaration is the actual command, which has «def» as one of its cases.
  • The next step is to find the elab or macro corresponding to this syntax. There are a few ways to do this; I'm still mostly using the old school method of searching for declaration] or «declaration»] looking for the builtinCommandElab for it, but you can also use "Find References" on declaration to get to it. That takes us to src4#Lean.Elab.Command.elabDeclaration
  • From there, we just go forward along the function calls looking for where the "real work" is. Declarations are one of the more complicated lean commands, so there is a lot of stuff, but if you imagine you are parsing a def you will try src4#Lean.Elab.Command.elabMutualDef, which calls src4#Lean.Elab.Term.elabMutualDef, which calls src4#Lean.Elab.addPreDefinitions, which calls src4#Lean.Elab.addAndCompileNonRec, which calls a private function that calls src4#Lean.addDecl.

Adam Topaz (Oct 07 2022 at 01:13):

Thanks Mario! That's very helpful!

Mario Carneiro (Oct 07 2022 at 01:22):

Actually we can even keep going:


Last updated: Dec 20 2023 at 11:08 UTC