Zulip Chat Archive
Stream: lean4
Topic: Re-assembling a TSyntax `tacticSeq
Scott Morrison (Oct 25 2022 at 00:21):
Suppose I've come across a list of TSyntax `tactic
s (e.g. that my decision procedure has suggested will solve a goal), and I would like to re-assemble these into a TSyntax `tacticSeq
. How do I do that?
import Lean
open Lean Syntax
def howDoI? (L : Array (TSyntax `tactic)) : TSyntax `Lean.Parser.Tactic.tacticSeq := by sorry
Scott Morrison (Oct 25 2022 at 00:21):
To #xy my problem, I'd like to make the following work:
import Lean
import Mathlib.Tactic.PermuteGoals
open Lean Syntax
def Lean.Syntax.TSepArray.ofElems {ks} {sep} (elems : Array (TSyntax ks)) : TSepArray ks sep :=
⟨mkSepArray elems (if sep.isEmpty then mkNullNode else mkAtom sep)⟩
def xy (n : Nat) (L : Array (TSyntax `tactic)) : TSyntax `tactic :=
let n : TSyntax `num := Syntax.mkNumLit <| toString n
let s : Syntax.TSepArray `tactic ";" := TSepArray.ofElems L
`(tactic| on_goal $n => $s) -- fails
This fails with error message
s has type
TSepArray `tactic ";" : Type
but is expected to have type
TSyntax `Lean.Parser.Tactic.tacticSeq : Type
and I'd like to bridge the gap. (Using indenting rather than semicolons is also a fine solution!)
Scott Morrison (Oct 25 2022 at 04:54):
@Gabriel Ebner, could I ping you on this one?
Gabriel Ebner (Oct 25 2022 at 04:55):
open Lean
variable (tacs : Array Syntax.Tactic)
#check `(by $tacs*)
#check `(by $tacs;*)
#check `(by $[$tacs]*)
#check `(by $[$tacs];*)
Gabriel Ebner (Oct 25 2022 at 04:55):
I was just about to collect all the options you have for antiquoting tacticSeqs! :smile:
Scott Morrison (Oct 25 2022 at 05:00):
Ah, too easy. :-) Is there a description somewhere of the antiquoting mechanism? I failed to discover these by reading the source code, even after thinking to look at antiquotations.
Scott Morrison (Oct 25 2022 at 05:00):
I guess it's just a matter of knowing examples to look at.
Scott Morrison (Oct 25 2022 at 05:34):
Gah, and how do I flatten a Array (TSyntax `tactic.seq)
to a TSyntax `tactic.seq
?
Scott Morrison (Oct 25 2022 at 05:37):
Or promote a TSyntax `tactic
to a singleton TSyntax `tactic.seq
?
Mario Carneiro (Oct 25 2022 at 05:40):
This seems like the wrong question. I pretty much never use tacticSeq
except insofar as it appears going in or out of syntax quotations. The main trick is that if $tac
is a tacticSeq then ($tac)
is a tactic, and $[$tac]*
will interpolate an array of tactics as a tacticSeq.
Scott Morrison (Oct 25 2022 at 05:41):
Perfect. ($tac)
was what I was missing.
Scott Morrison (Oct 25 2022 at 05:42):
Is there a multi-line version of ($tac)
? i.e. no parentheses and semicolons.
Mario Carneiro (Oct 25 2022 at 05:43):
yes, you can do (tac \n tac)
too
Mario Carneiro (Oct 25 2022 at 05:43):
the parentheses are required though
Scott Morrison (Oct 25 2022 at 05:44):
But I'm starting from a tacticSeq...?
Mario Carneiro (Oct 25 2022 at 05:45):
I think you need to #xy
Scott Morrison (Oct 25 2022 at 05:45):
The example I'm fighting with is meant to be
constructor
on_goal 1 =>
exact 37
exact 37
Scott Morrison (Oct 25 2022 at 05:45):
But it's coming out as (constructor; on_goal 1 => (exact 37); exact 37)
, where the second exact 37
applies also to goal 1
Mario Carneiro (Oct 25 2022 at 05:46):
don't use semicolons?
Mario Carneiro (Oct 25 2022 at 05:46):
that seems like a parenthesizer error though
Scott Morrison (Oct 25 2022 at 05:46):
Let me #xy for a moment. I'm not writing this by hand.
Gabriel Ebner (Oct 25 2022 at 06:06):
I think it's worth pointing out that simp; assumption
is not a tactic. (Although some parts of the system pretend it is by wrapping the two tactics in a mkNullNode
, but that's a story for another day..)
Gabriel Ebner (Oct 25 2022 at 06:08):
You should probably use Array Syntax.Tactic
everywhere, and only convert to a tactic on the top-level. (With parens for now.) Then you can store simp; assumption
as two tactics. We'll figure something out for the code actions eventually so that we can replace a tactic by a sequence of tactics.
Scott Morrison (Oct 25 2022 at 06:16):
Okay, sorry for the delay, here's an #xy:
import Lean
import Mathlib.Tactic.PermuteGoals
open Lean Meta Elab Tactic Syntax
/-- A representation of a semi-structured
(i.e. only uses `on_goal` for structuring) tactic script. -/
inductive Script : Type
| single : Syntax.Tactic → Script
| step : Syntax.Tactic → Script → Script
| on_goal : Nat → Script → Script → Script
def Script.compile : Script → MetaM Syntax.Tactic
| .single s => `(tactic| $s)
| .step s S => do
let S ← S.compile
`(tactic| ($s; $S))
| .on_goal n a b => do
let n := Syntax.mkNumLit <| toString (n+1)
let a ← a.compile
let b ← b.compile
`(tactic| (on_goal $n => $a); $b) -- fails, a is not a TSyntax `tactic.seq
def test : MetaM Script := do
pure (.step (← `(tactic| constructor)) (.on_goal 0 (.single (← `(tactic| exact 42))) (.single (← `(tactic| exact 37)))))
elab "test" : tactic => do
let script ← test
let tac ← script.compile
evalTactic tac
def f : Nat × Nat := by test
example : f = (42, 37) := rfl
Scott Morrison (Oct 25 2022 at 06:16):
But I will in any case go and rethink this having seen @Gabriel Ebner's suggestion.
Mario Carneiro (Oct 25 2022 at 06:20):
One approach might be to take a page from the infoTree implementation and have a monad which stores a Array Syntax.Tactic
in the state, and then you have the following operations:
pushTactic : Syntax.Tactic -> M Unit
: insert a new tactic node in the statewithOnGoal : Nat -> M Unit -> M Unit
: First stash the state intacs
and clear it, then run the continuation. Retrieve the new statetacs'
, and construct(on_goal $n => $tacs')
and push it totacs
and restore the state.
Scott Morrison (Oct 25 2022 at 06:27):
I guess I'm not sure what problem a monad is solving here. It sounds like you want to do something intertwined with the tactic discovery process? That seems like unnecessary complication. I'm happy with some intermediate representation describing the structure of the proof, and am just looking for a way to synthesize the Array Syntax.Tactic
from it.
Mario Carneiro (Oct 25 2022 at 06:33):
Well, all of your tactics need to do some proof recording as well, right? The manual version of what I just said would be to pass an Array Syntax.Tactic
in and out of all the augmented tactics (or just out and append everything together). It will be a lot of common bookkeeping compared to having the monad handle it
Mario Carneiro (Oct 25 2022 at 06:34):
anyway, I agree with Gabriel that the "intermediate representation describing the structure of the proof" can be Array Syntax.Tactic
; the monad is just a way to put stuff together transparently.
Scott Morrison (Oct 25 2022 at 06:37):
Okay. I appreciate the point about the monad, and I'll try that later, but it's orthogonal to my immediate problem. However I think I've got it now.
Mario Carneiro (Oct 25 2022 at 06:38):
Here's a working version of your example BTW:
import Lean
open Lean
syntax "on_goal " num " => " tacticSeq : tactic
/-- A representation of a semi-structured
(i.e. only uses `on_goal` for structuring) tactic script. -/
inductive Script : Type
| single : Syntax.Tactic → Script
| step : Syntax.Tactic → Script → Script
| on_goal : Nat → Script → Script → Script
def Script.compile : Script → Array Syntax.Tactic → MetaM (Array Syntax.Tactic)
| .single s, acc => return acc.push s
| .step s S, acc => S.compile (acc.push s)
| .on_goal n a b, acc => do
let n := Syntax.mkNumLit <| toString (n+1)
let a ← a.compile #[]
b.compile (acc.push (← `(tactic| on_goal $n => $a))
Scott Morrison (Oct 25 2022 at 06:44):
I had come up with
/-- A representation of a semi-structured
(i.e. only uses `on_goal` for structuring) tactic script. -/
inductive Script : Type
| step : Syntax.Tactic → Script
| array : Array Script → Script
| on_goal : Nat → Script → Script
partial def Script.compile : Script → MetaM (Array (Syntax.Tactic))
| .step s => do pure #[← `(tactic| $s)]
| .array a => do
pure (← a.mapM compile).flatten
| .on_goal n a => do
let n := Syntax.mkNumLit <| toString (n+1)
let a ← a.compile
pure #[← `(tactic| on_goal $n => $[$a]*)]
(so with a different definition of Script
, but whatever). Thanks for this, I will be able to use some combination of these.
Last updated: Dec 20 2023 at 11:08 UTC