Zulip Chat Archive
Stream: lean4
Topic: macro v/s typeclass resolution
Siddharth Bhat (Sep 29 2021 at 23:30):
How do I write a macro which captures something like "x" + "y"
into an abstract syntax tree? Currently, it appears to cause a typeclass lookup for the HAdd
typeclass. Here's a minimal example of what I want:
-- Controlling typeclass resolution versus macros
inductive Arith: Type :=
| Add : Arith -> Arith -> Arith
| Symbol : String -> Arith
declare_syntax_cat arith
syntax term : arith
syntax arith "+" arith : arith
syntax "fromArith% " arith : term
macro_rules
| `(fromArith% $sym:term) => `(Arith.Symbol $sym)
| `(fromArith% $x:arith + $y:arith ) => `(Arith.Add (fromArith% $x) (fromArith% $y))
macro "arith" n:ident "->" e:arith : command =>
`(def $n:ident : Arith := fromArith% $e)
arith baz -> "x" + "y"
#print baz
I would like the answer to be:
def baz : Arith :=
Arith.Add (Arith.Symbol "x") (Arith.Symbol "y")
I currently get the error:
add.lean:19:13: error: failed to synthesize instance
HAdd String String ?m.1645
def baz : Arith :=
Arith.Symbol (sorryAx String)
Mario Carneiro (Sep 29 2021 at 23:33):
I think you have to specify the precedence here, because in the expression fromArith% "x" + "y"
it could mean either fromArith% ("x" + "y")
or (fromArith% "x") + "y"
, and it seems lean is going for the latter interpretation, which is not what you want
Mario Carneiro (Sep 29 2021 at 23:38):
Additionally, you have an ambiguity due to the syntax term : arith
rule, since then even fromArith% ("x" + "y")
can be interpreted as fromArith% ("x" + "y" : term)
Mario Carneiro (Sep 29 2021 at 23:41):
Testing reveals that this latter version is how it is actually getting interpreted
Mario Carneiro (Sep 29 2021 at 23:43):
The simplest fix is something like this:
declare_syntax_cat arith
syntax strLit : arith
syntax arith "+" arith : arith
syntax:max "fromArith% " arith : term
macro_rules
| `(fromArith% $sym:strLit) => `(Arith.Symbol $sym)
| `(fromArith% $x:arith + $y:arith ) => `(Arith.Add (fromArith% $x) (fromArith% $y))
macro "arith" n:ident "->" e:arith : command =>
`(def $n:ident : Arith := fromArith% $e)
arith baz -> "x" + "y"
#print baz
Siddharth Bhat (Sep 29 2021 at 23:44):
Ah, strLit
is handy to know. I wonder if there's a place to find all of the core syntax categories?
Leonardo de Moura (Sep 29 2021 at 23:45):
If you want to use identifiers, you can add the following lines after Mario's example above.
syntax ident : «arith» -- Have to use french quotes since `arith` is now a keyword
macro_rules
| `(fromArith% $x:ident) => `(Arith.Symbol $(Lean.quote (toString x.getId)))
arith foo -> x + y + z
#print foo
syntax "{" term "}" : «arith» -- escape for embedding terms into `Arith`
macro_rules
| `(fromArith% { $e }) => e
arith boo -> x + y + {foo}
#print boo
Last updated: Dec 20 2023 at 11:08 UTC