Zulip Chat Archive

Stream: new members

Topic: leading_parser?


Eduardo Ochs (May 13 2024 at 16:35):

People, where can I find more about leading_parser? It appears many times in the source but I couldn't find mentions to it in any of the books, and its definition (???) in Lean/Elab/BuiltinNotation.lean is too difficult to read (IMO) and doesn't have comments...

Thanks in advance! :oh_no:

Eduardo Ochs (May 13 2024 at 16:44):

Aha, I just found this message by @Kyle Miller! Let me change my question...

Where can I find examples of how to translate calls to "leading_parser" to calls to "syntax"?

Kyle Miller (May 13 2024 at 17:59):

Usually it's ">> becomes space and f x y z becomes f(x, y, z)" though sometimes the parser name for syntax can be a little different.

There are also transformations like many p becomes p* and many1 p becomes p+, among some others.

Eduardo Ochs (May 17 2024 at 06:43):

Hi, another question...

I decided to inspect the objects created by leading_parser, and I got this, after a lot of trial and error:

import Lean.Parser.Types
namespace Lean
namespace Parser
def foo := leading_parser "bar "
#check foo
#check foo.info
#check foo.info.firstTokens

def a := foo.info.firstTokens
def b := Lean.Parser.FirstTokens.tokens ["$", "bar"]
#eval a
#eval b

Here a and b are "equal" but not "eq".

Is there an easy way to print the structure of a? My guess - as a newbie - is: "no because FirstTokens doesn't derive Repr, but there are workarounds using instances".

Is that right? Is it possible to make FirstTokens an instance of Repr? If yes, how?

Thanks in advance!

Kyle Miller (May 17 2024 at 20:49):

What's the question about a and b not being "eq"? They're equal according to

example : a = b := rfl

Kyle Miller (May 17 2024 at 20:51):

(With import Lean imported, #eval a prints [$, bar]. I'm not sure what you're seeing, since your mwe fails on leading_parser for me on a version near Lean 4.8.0-rc1)

Kyle Miller (May 17 2024 at 20:52):

no because FirstTokens doesn't derive Repr, but there are workarounds using instances

Note that "deriving Repr" means "try to automatically create a Repr instance". Mentioning that in case you think instances are some sort of workaround.

Kyle Miller (May 17 2024 at 20:54):

This is the easiest way to see what leading_parser is doing:

def foo := leading_parser "bar "

#print foo
/-
def Lean.Parser.foo : Parser :=
withCache `Lean.Parser.foo
  (withAntiquot (mkAntiquot "foo" `Lean.Parser.foo true) (leadingNode `Lean.Parser.foo 1024 (symbol "bar ")))
-/

It's a macro that expands to that. The key thing it does is embed the declaration name for foo into itself, in the leadingNode parser combinator. That's what creates a Syntax.node with Lean.Parser.foo as the kind.

Kyle Miller (May 17 2024 at 20:55):

The antiquote business is for parsing `(... $x:foo ...) in syntax quotations in syntactically correct locations.

Eduardo Ochs (May 18 2024 at 01:32):

About "eq" and "equal", I was thinking about this:

(eq    '(a b) '(a b))  ;-> nil
(equal '(a b) '(a b))  ;-> t

It didn't occur to me that we could test "equal"ity in Lean using "example : a = b := rfl"... neat!

Eduardo Ochs (May 18 2024 at 01:37):

Now about the output of "#print foo": wow and thanks! It works here, but I think that I need to understand other things before understanding that... and my guess is that would be a good idea to start by understand how "deriving Repr" works in a simple case. I tried this,

inductive myNat where
  | zero             : myNat
  | succ (n : myNat) : myNat
  deriving Repr

def my1 := myNat.succ myNat.zero
#check my1
#eval  my1
#print my1
#check repr my1
#eval  repr my1
#print repr my1
#check Std.Format

and then:

1) the method "repr" for the type myNat is not in a super-obvious place, like in myNat.repr,

2) the output of "#check repr my1" is "repr my1 : Std.Format", and I don't have test snippets (yet) for the class Std.Format,

3) but I read some parts of the source starting by "mkReprInstanceHandler" and I found references to "isInductive" and "getStructureFields" - they look very useful, can we start by them? If yes, question: how do I call "isInductive" and "getStructureFields" on the "myNat" or on the "my1" of the example above?

Thanks in advance!

Kyle Miller (May 18 2024 at 03:26):

Here's how you can get the name of the instance:

#synth Repr myNat
-- instReprMyNat

Kyle Miller (May 18 2024 at 03:27):

Unfortunately you reach a dead end quick because the deriving handler defines a constant with an inaccessible name:

#print instReprMyNat
/-
def instReprMyNat : Repr myNat :=
{ reprPrec := reprmyNat✝ }
-/

Kyle Miller (May 18 2024 at 03:30):

Though if you set set_option trace.Elab.command true you can see what deriving constructs.

Kyle Miller (May 18 2024 at 03:32):

Here, if you want to see:

open Lean

def reprmyNat (n : myNat) (prec : Nat) : Format :=
  match n with
  | myNat.zero =>
    Repr.addAppParen
      (Format.group (Format.nest (if prec >= max_prec then 1 else 2) (Std.Format.text "myNat.zero"))) prec
  | @myNat.succ a =>
    Repr.addAppParen
      (Format.group
        (Format.nest (if prec >= max_prec then 1 else 2)
          (Std.Format.text "myNat.succ" ++ Format.line ++ reprmyNat a max_prec)))
      prec

instance : Repr myNat where
  reprPrec := reprmyNat

Kyle Miller (May 18 2024 at 03:34):

Repr instances aren't so interesting. They're just code to turn data into some string representation (using Format so that indentation is taken care of). I would not suggest going deep into the derive handler unless you're willing to venture forth into the less-documented parts of Lean. (You might look at the Lean 4 Metaprogramming Book to get an idea of how some of the system works, but it's not comprehensive yet.)

Repr doesn't have anything to do with #print. What #print does is pretty print a declaration, whose value is an Expr.

Kyle Miller (May 18 2024 at 03:37):

Re Lisp-like eq vs equal, in Lean the main equality type Eq is more like equal, and there's no such thing as eq unless you are willing to do unsafe things. The Eq is true mathematical equality. There's also BEq for user-defined equality operations.


Last updated: May 02 2025 at 03:31 UTC