Zulip Chat Archive
Stream: lean4
Topic: Antiquot Splice
Marcus Rossel (Sep 08 2022 at 07:38):
I'm not sure if this title makes sense.
I'm trying to write a command that transforms something of the form
my_cmd [a : Nat, b : String, c : Bool × Prop]
into
example : IgnoreMe → Type :=
fun x => match x with
| a => Nat
| b => String
| c => Bool × Prop
My problem is that I don't know how to do the splicing in the antiquotation:
declare_syntax_cat interface_var
syntax ident " : " term : interface_var
macro "my_cmd" "[" vars:interface_var,* "]" : command => do
`(
example : IgnoreMe → Type :=
fun x => match x with ???
)
Is there a way to use $[ ]*
for this?
Mario Carneiro (Sep 08 2022 at 07:58):
declare_syntax_cat interface_var
syntax ident " : " term : interface_var
macro "my_cmd" "[" vars:interface_var,* "]" : command => do
let args := vars.getElems.map fun
| `(interface_var| $x:ident : $t) => (x, t)
| _ => panic! ""
let (lhs, rhs) := args.unzip
`(
example : IgnoreMe → Type :=
fun x => match x with
$[| $lhs => $rhs]*
)
Marcus Rossel (Sep 08 2022 at 11:50):
I've run straight into the next thing I can't figure out :sweat_smile:
Let's say I was trying to build a command my_multi
which gets a sequence of lists and then runs my_cmd
on each one:
import Lean
open Lean Macro
declare_syntax_cat interface_var
syntax ident " : " term : interface_var
declare_syntax_cat interface_scheme
syntax "[" interface_var,* "]" : interface_scheme
def getInterfaceVarComponents : (TSyntax `interface_var) → MacroM (Ident × Term)
| `(interface_var| $i:ident : $t) => return (i, t)
| _ => throwUnsupported
def getInterfaceSchemeVars : (TSyntax `interface_scheme) → MacroM (Array $ TSyntax `interface_var)
| `(interface_scheme| [ $vars,* ]) => return vars
| _ => throwUnsupported
macro "my_cmd" scheme:interface_scheme : command => do
let vars ← getInterfaceSchemeVars scheme
let components ← vars.mapM getInterfaceVarComponents
let ⟨ids, types⟩ := components.unzip
`(
example : IgnoreMe → Type :=
fun x => match x with $[| $ids => $types]*
)
macro "my_multi" schemes:interface_scheme* : command => do
`($[my_cmd $schemes:interface_scheme]*) -- Error
Then the last line here gives me multiple errors, e.g. elaboration function for 'commandMy_cmd_' has not been implemented
.
Is this Lean telling mean that my_cmd
is not implemented?
Gabriel Ebner (Sep 08 2022 at 12:05):
That's an ugly (and old) part of the syntax system.
Gabriel Ebner (Sep 08 2022 at 12:06):
`(foo)
is sadly heavily overloaded. It can either produce:
- A term quotation (i.e., of category
term
) - A command quotation (i.e., of category
command
), or - A command list quotation (i.e., mkNullNode of commands)
Gabriel Ebner (Sep 08 2022 at 12:10):
Many places that accept commands also accept these "command lists", but not everywhere. Notably the pretty printer crashes on these hacky command lists:
import Lean
open Lean PrettyPrinter Elab Command
elab "foo" : command => do
logInfo <| ← liftCoreM do ppCommand (← `(#check 0 #check 0))
foo -- unknown constant 'null'
(even though the quotation has type Syntax.Command
)
Gabriel Ebner (Sep 08 2022 at 12:11):
More relevant in your case here: the command list version explicitly does not come with an antiquotation (it uses many1NoAntiquot
). So you can't write `($[command]*)
, no matter what command it is.
Gabriel Ebner (Sep 08 2022 at 12:14):
With that in mind, the solution is clear: all you need to do is call mkNullNode
yourself.
macro "my_multi" schemes:interface_scheme* : command =>
return mkNullNode (← schemes.mapM (`(my_cmd $(·))))
Marcus Rossel (Sep 08 2022 at 12:25):
Gabriel Ebner said:
That's an ugly (and old) part of the syntax system.
Haha, thank you for the history lesson :heart:️
Last updated: Dec 20 2023 at 11:08 UTC