Zulip Chat Archive

Stream: general

Topic: random parser facts


Mario Carneiro (Mar 12 2019 at 00:07):

New discovery while reading the lean source: These are both legal:

structure foo := mk
structure bar := mk ::

and they add a new type isomorphic to unit. (I would have guessed that the second one works, but the first one is a parser trick.) However these don't work:

structure bad
structure bad.
structure bad :=

Kenny Lau (Mar 12 2019 at 00:16):

who would read the lean source...

Mario Carneiro (Mar 12 2019 at 00:18):

how else do you learn about undocumented features (and "features")?

Mario Carneiro (Mar 12 2019 at 00:56):

aha, here is the random parser fact I was looking for: You may know that you can write {} before the binder of a structure or inductive to make the arguments implicit. This is used for example to make list.nil have no explicit args:

structure regular1 (α : Type) (l : list α) := mk :: (foo : nat)
inductive regular2 (α : Type) (l : list α) | mk : regular2

#check @regular1.mk -- regular1.mk : Π {α : Type} (l : list α), ℕ → regular1 α l
#check @regular1.foo -- Π {α : Type} {l : list α}, regular1 α l → ℕ
#check @regular2.mk -- regular2.mk : Π {α : Type} (l : list α), regular2 α l

structure implicit1 (α : Type) (l : list α) := mk {} :: (foo {} : nat)
inductive implicit2 (α : Type) (l : list α) | mk {} : implicit2

#check @implicit1.mk -- implicit1.mk : Π {α : Type} {l : list α}, ℕ → implicit1 α l
#check @implicit1.foo -- implicit1.foo : Π {α : Type} {l : list α}, implicit1 α l → ℕ
#check @implicit2.mk -- implicit2.mk : Π {α : Type} {l : list α}, implicit2 α l

It turns out there is a third mode, triggered by () before the colon instead. But the parser code here is buggy, so you have to put a space between the parens so it doesn't look like the unit star token:

structure explicit1 (α : Type) (l : list α) := mk ( ) :: (foo ( ) : nat)
inductive explicit2 (α : Type) (l : list α) | mk ( ) : explicit2

#check @explicit1.mk -- explicit1.mk : Π (α : Type) (l : list α), ℕ → explicit1 α l
#check @explicit1.foo -- explicit1.foo : Π (α : Type) (l : list α), explicit1 α l → ℕ
#check @explicit2.mk -- explicit2.mk : Π (α : Type) (l : list α), explicit2 α l

Kenny Lau (Mar 12 2019 at 00:58):

so every def is invoking an instance of the axiom schema...

Mario Carneiro (Mar 12 2019 at 00:58):

nonsequitur much?

Kenny Lau (Mar 12 2019 at 00:59):

yeah sorry it's a random remark

Mario Carneiro (Mar 12 2019 at 01:00):

I suppose random facts are on topic here

Kenny Lau (Mar 12 2019 at 01:00):

so what do you think anyway

Kenny Lau (Mar 12 2019 at 01:00):

every structure / inductive / class / def is invoking an axiom of the axiom schema, all in the name of definitional equalities

Kenny Lau (Mar 12 2019 at 01:00):

I suppose there's no way around this

Mario Carneiro (Mar 12 2019 at 01:04):

I literally have no idea what you are talking about. It's not related to the context on this thread as far as I can tell

Kenny Lau (Mar 12 2019 at 01:05):

I mean, when you create an inductive type, you're effectively adding axioms to the system right

Mario Carneiro (Mar 12 2019 at 01:12):

yes, inductive is a mechanism for using an axiom schema built into lean. structure and class are fancy ways to say inductive, and def is not an axiom in any sense

Kenny Lau (Mar 12 2019 at 01:13):

you're adding a new constant and adding an axiom that the constant "unfolds" to a certain value

Kenny Lau (Mar 12 2019 at 01:13):

when you say def n := 5 you're adding the constant n : nat and the axiom n._equations._eqn_1 : n = 5

Mario Carneiro (Mar 12 2019 at 01:14):

you're adding a new constant and adding an axiom that the constant "unfolds" to a certain value

no, definitions in DTT don't work like this

Mario Carneiro (Mar 12 2019 at 01:15):

they are abbreviations for certain terms, so there is no axiom of equality

Kenny Lau (Mar 12 2019 at 01:15):

I see

Mario Carneiro (Mar 12 2019 at 01:15):

but for practical reasons definitions are supported by the kernel, which implements definition unfolding as a reduction rule

Sebastian Ullrich (Mar 13 2019 at 09:25):

Ooh, good topic. Did you know that you can let-bind notations like in

#eval let infix + := nat.mul in 1 + 2

? Is anybody using that? Because implementing that in pure Lean is basically impossible and so this will probably not work in Lean 4 and I wonder if anybody will even notice.

Mario Carneiro (Mar 13 2019 at 09:26):

what? news to me

Sebastian Ullrich (Mar 13 2019 at 09:27):

Yeah, me too until I read the source some time ago

Mario Carneiro (Mar 13 2019 at 09:27):

that's pretty cool though

Mario Carneiro (Mar 13 2019 at 09:28):

I like the idea of expression-local notations

Sebastian Ullrich (Mar 13 2019 at 09:28):

Well, don't get too attached to it :sweat_smile:

Mario Carneiro (Mar 13 2019 at 09:28):

structure has something similar with those (infix bla) binders

Sebastian Ullrich (Mar 13 2019 at 09:29):

Yes, that's okay (more or less, it's a pain in the macro expander), because the extended parser (terms) is not the one being executed (commands)

Mario Carneiro (Mar 13 2019 at 09:29):

What about an infix tactic? How hard is that?

Mario Carneiro (Mar 13 2019 at 09:30):

that seems more doable and just as expressive

Mario Carneiro (Mar 13 2019 at 09:31):

I hope the parser isn't going to end up being a second tactic language

Sebastian Ullrich (Mar 13 2019 at 09:31):

That's not much better (or worse) because tactic parsing is still part of the big term parser recursion

Mario Carneiro (Mar 13 2019 at 09:32):

oh, I see... you won't be able to parse the following expressions until you run the tactic

Mario Carneiro (Mar 13 2019 at 09:33):

but you can't run the tactic until you've parsed the tactic block

Mario Carneiro (Mar 13 2019 at 09:33):

okay, I'm convinced... kill it with fire

Sebastian Ullrich (Mar 13 2019 at 09:33):

Yes, it would not be a true tactic but part of the tactic block notation. Then it's no harder or easier than notation-let

Sebastian Ullrich (Mar 13 2019 at 09:34):

So let's just pretend this feature has never existed...

Mario Carneiro (Mar 13 2019 at 09:35):

but what about expressions that we want to parse with a parser that we don't have at parse time? I was thinking more like a real infix tactic

Mario Carneiro (Mar 13 2019 at 09:36):

Some kind of super quoting expression should be available

Mario Carneiro (Mar 13 2019 at 09:37):

This is also important for many custom parsers... for example if I want to have a block of code in another language inline and parse it with a custom parser

Johan Commelin (Mar 13 2019 at 09:41):

Would this allow us to take a step towards unifying group and add_group and still have natural notation?

Sebastian Ullrich (Mar 13 2019 at 09:49):

@Mario Carneiro I'm not sure I'm following. When using a DSL, you usually statically know its grammar and where it can occur in the Lean grammar (e.g. "as the second argument to this tactic"). Then everything works out.

Mario Carneiro (Mar 13 2019 at 09:50):

heh, I'm familiar with lots of languages where the grammar is not statically known (hint: lean is one of them)

Sebastian Ullrich (Mar 13 2019 at 09:51):

It's certainly not changed at tactic execution time

Mario Carneiro (Mar 13 2019 at 09:51):

I was thinking of parsing more like "read random junk until you see STOP_NOW"

Mario Carneiro (Mar 13 2019 at 09:53):

and then you might have to read another file (analogous to lean imports or oleans) to tell you what tokens are valid and how to parse them

Mario Carneiro (Mar 13 2019 at 09:53):

and this happens from lean's perspective at tactic execution time

Kevin Buzzard (Mar 13 2019 at 11:27):

All I want to know is whether we'll be able to do {t * s for t in T, s in S if t \ne 7} for S and T subsets of a monoid

Sebastian Ullrich (Mar 13 2019 at 11:31):

Oh that's trivial


Last updated: Dec 20 2023 at 11:08 UTC