Zulip Chat Archive
Stream: lean4
Topic: Syntax of tactic sequence
Jon Eugster (Aug 25 2023 at 13:28):
I'm trying to understand lean's Syntax
better, in particular tacticSeq1Indented
.
In particular this is a Syntax.node info `tacticSeq1Indented args
where args
is an Array Syntax
containing a single null-node Syntax.node info `null args2
. Now args2
is another Array Syntax
containing the tactics of the sequence, but also another null-node Syntax.node info `null #[]
between any two tactics.
Can anybody explain what the function of these null-nodes is? I don't understand either use case and naively have the impression that everything would work just as well if they didn't exist.
below is a #mwe that matches the syntax of args
for demonstration
MWE
Mario Carneiro (Aug 25 2023 at 13:32):
the null nodes are the separators between tactics, they are actually optional ";"
Mario Carneiro (Aug 25 2023 at 13:32):
check out what happens if you use simp;
instead of simp
Jon Eugster (Aug 25 2023 at 13:34):
Then you get a Syntax.atom info ";"
in between the two tactics instead, yes.
Jon Eugster (Aug 25 2023 at 13:34):
And the first null-node wrapping the list?
Mario Carneiro (Aug 25 2023 at 13:37):
that's the list itself
Mario Carneiro (Aug 25 2023 at 13:38):
it gets packed up as one argument because tacticSeq1Indented
itself has one argument, which is a tactic;*
(more or less)
Jon Eugster (Aug 25 2023 at 13:47):
ah and it would be impossible in lean to define tacticSeq1Indented
with arbitrary number of arguments, I guess?
and likewise I assume it would be more effort to find out if the next entry was a ";" or a new tactic, so it just inserts a null-node and then assumes that every other node is just a separator?
Thanks for the explanation!
Mario Carneiro (Aug 25 2023 at 13:48):
not impossible, just irregular
Mario Carneiro (Aug 25 2023 at 13:49):
it helps to have some standardized structure in syntax so that stuff like syntax-match works properly
Mario Carneiro (Aug 25 2023 at 13:50):
basically the only variadic syntaxes are many
,many1
, sepBy
, sepBy1
and they all produce null nodes
Mario Carneiro (Aug 25 2023 at 13:50):
and "regular" syntax node constructors all have a statically known number of arguments
Mario Carneiro (Aug 25 2023 at 13:51):
(this was not always the case, but exceptions usually ended up as bug reports because something wouldn't handle them correctly)
Jon Eugster (Aug 25 2023 at 13:58):
I see, that makes sense!
I was a bit confused because I tried to parse a tactic sequence removing all occurences of a tactic Hint
and I thought it looked a bit cumbersome:
match args with
| [] => []
-- delete all `Hint` occurences in the middle of the sequence.
| Syntax.node _ `GameServer.Tactic.Hint _ :: _ :: r
filterArgs r
-- delete `Hint` occurence at the end of the sequence
| Syntax.node _ `GameServer.Tactic.Hint _ :: []
[]
-- just recurse over any other type of syntax
| a :: rest =>
replaceHoles a :: filterArgs rest
(where replaceHoles
and filterArgs
are the recursive functions containing this snippet)
Sebastian Ullrich (Aug 25 2023 at 14:59):
Was there some part that did not work out with syntax quotation patterns?
Jon Eugster (Aug 25 2023 at 15:19):
probably only that I don't know how to use them...
Jon Eugster (Aug 25 2023 at 15:21):
I want to take a sequence of tactics and execute it, but also store it as a string ("template") where I delete my custom tactics that appear within that tactic block:
roughly this non-mwe
def replaceHoles (tacs : Syntax) : Syntax :=
match tacs with
| Syntax.node info kind ⟨args⟩ => Syntax.node info kind ⟨filterArgs args⟩
| other => other
where filterArgs (args : List Syntax) : List Syntax :=
match args with
| [] => []
-- replace `Hole` with `sorry`.
| Syntax.node info `GameServer.Tactic.Hole _ :: r =>
Syntax.node info `Lean.Parser.Tactic.tacticSorry #[Syntax.atom info "sorry"] :: filterArgs r
-- delete all `Hint` and `Branch` occurences in the middle.
| Syntax.node _ `GameServer.Tactic.Hint _ :: _ :: r
| Syntax.node _ `GameServer.Tactic.Branch _ :: _ :: r =>
filterArgs r
-- delete `Hint` and `Branch` occurence at the end of the tactic sequence.
| Syntax.node _ `GameServer.Tactic.Hint _ :: []
| Syntax.node _ `GameServer.Tactic.Branch _ :: [] =>
[]
-- Recurse on all other Syntax.
| a :: rest =>
replaceHoles a :: filterArgs rest
elab "Template" tacs:tacticSeq : tactic => do
-- evaluate the tactic sequence
Tactic.evalTactic tacs
-- now save a string version of this tactic block
let newTacs : TSyntax `Lean.Parser.Tactic.tacticSeq := ⟨replaceHoles tacs.raw⟩
let template ← PrettyPrinter.ppCategory `Lean.Parser.Tactic.tacticSeq newTacs
pure () -- more stuff
is this the wrong approach? (i.e. is there a higher level way of doing this?)
Last updated: Dec 20 2023 at 11:08 UTC