Zulip Chat Archive

Stream: lean4

Topic: Pretty printing Syntax fails


Reinier van der Gronden (Jul 22 2022 at 11:19):

I'm writing a tactic that gives suggestions on how to change existing tactics to be more legible. This delaborates the goal and combines this with the executed tactic:

let newGoalStx  delab ( instantiateMVars newGoalDecl.type)
let newStx  `(suffices $newGoalStx by $tacticStx)
addTrace `structured m!"{newStx}"

The newStx object itself seems valid, however adding the trace fails with the error message:

[structured] [Error pretty printing syntax: parenthesize: uncaught backtrack exception. Falling back to raw printer.]
(Term.suffices
 "suffices"
 (Term.app `Even [(num "0")])
 []
 (Term.byTactic
  "by"
  (Tactic.tacticSeq
   (Tactic.tacticRepeat_
    "repeat"
    (Tactic.tacticSeq
     (Tactic.tacticSeq1Indented
      [(group (Tactic.apply "apply" (Term.app `Even.add_two [(Term.hole "_") (Term.hole "_")])) [])]))))))

Why does this fail? This Syntax 'raw' printing seems in line with what I expect: suffices Even 0 by repeat apply Even.add_two _ _

Sebastian Ullrich (Jul 22 2022 at 11:23):

No, that syntax tree is missing the sufficesDecl node. Try $newGoalStx:term.

Sebastian Ullrich (Jul 22 2022 at 11:25):

Actually do you have an #mwe? This should be a type error in recent versions.

Reinier van der Gronden (Jul 22 2022 at 11:34):

What do you mean by the sufficesDecl node? I've tried adding :term, but then the $tacticStx complains with expected term.

Reinier van der Gronden (Jul 22 2022 at 11:34):

I'll try creating a mwe for it, good practice anyways

Reinier van der Gronden (Jul 22 2022 at 11:36):

Also, I've updated to the latest nightly and the error remains the same. Note that I have set pp.rawOnError, so it could still be a type error I guess? VSCode doesn't complain though

Reinier van der Gronden (Jul 22 2022 at 12:10):

Okay that took longer than expected, I tried to trim it down a little too much. The smallest example without changing the structure of my tactic is:

import Lean
open Lean Lean.Meta Lean.Elab Lean.Elab.Tactic Lean.PrettyPrinter
set_option pp.rawOnError true

inductive Even : Nat  Prop
| zero : Even Nat.zero
| add_two :  k : Nat, Even k  Even (k+2)

def x (stx : Syntax): TacticM Unit := do
  evalTactic stx
  match  getUnsolvedGoals with
  | [goal] =>
    let goalStx  delab ( instantiateMVars ( getMVarDecl goal).type)
    let newStx  `(suffices $goalStx by $stx)
    addTrace `myTactic m!"This message fails with \n{newStx}"
  | _ => logWarning "MWE"

elab &"myTactic " t:tactic : tactic =>
  x t

example : Even 2 := by
  myTactic apply Even.add_two _ _
  sorry

Sebastian Ullrich (Jul 22 2022 at 12:12):

That doesn't parse for me on current master. "expected ';' or line break" after $goalStx.

Reinier van der Gronden (Jul 22 2022 at 12:20):

Ah yes, my toolchain was still overriden with an old nightly :sweat_smile: I get the same error now

Sebastian Ullrich (Jul 22 2022 at 12:22):

I'm starting to wonder whether we should remove toolchain overrides as a mis-feature from elan

Reinier van der Gronden (Jul 22 2022 at 12:23):

Well the weird thing to me was that I had removed the lean.toolchain from the working directory, but it was overriden by a parent directory that had it. But that might also just be me mismanaging my folder structure :sweat_smile: I haven't worked with Lean 4 that much yet

Henrik Böving (Jul 22 2022 at 12:23):

Sebastian Ullrich said:

I'm starting to wonder whether we should remove toolchain overrides as a mis-feature from elan

But it's used in the compiler development process right? At least as documented in the manual.

Sebastian Ullrich (Jul 22 2022 at 12:26):

Not by me, but you're right, yes :sweat_smile: . A lean-toolchain file with contents a la ../build/release/stage0 would be much more explicit and discoverable though.

Henrik Böving (Jul 22 2022 at 12:29):

Damn NixOS punks :P

Marc Huisinga (Jul 22 2022 at 13:38):

Sebastian Ullrich said:

I'm starting to wonder whether we should remove toolchain overrides as a mis-feature from elan

I use it for CI

Sebastian Ullrich (Jul 22 2022 at 13:39):

You can use lake +leanprover/lean4:nightly build for that

Sébastien Michelland (Jul 22 2022 at 13:53):

I find switching toolchains in VS Code to be quite intuitive/discoverable. Admittedly, it is confusing when a change to lean-toolchain doesn't propagate because of the override. If you get rid of the override, maybe a similar menu command that would instead modify lean-toolchain then restart the server could be provided?

Sebastian Ullrich (Jul 22 2022 at 13:54):

AFAIK switching toolchains in VS Code does not actually use elan overrides

Reinier van der Gronden (Jul 25 2022 at 09:19):

So in my m(notworking)e above, I changed the line

let newStx  `(suffices $goalStx:term by $stx:tactic; exact this; _)

Where I'm unsure on how to 'finish' the syntax quotation. Looking at the macro definition of suffices, we see the second match case:

  | `(suffices $[$x :]? $type by%$b $tac:tacticSeq; $body) => `(have $[$x]? : $type := $body; by%$b $tac:tacticSeq)

Here I don't know all the notation, but I do see that it expects a sequence of tactics, ending with a body element, that is used as a (I assume) proof term outside of tactic mode. In my case, I do not see why I need such a body term. My case would be pretty simple: suffices Even 0 by repeat apply Even.add_two _ _ only contains the tacticSeq, right?

Could someone elaborate on the purpose of the body term? Is there some way I can consider it 'empty' in my case?

Reinier van der Gronden (Jul 26 2022 at 09:37):

An actual compilable mwe that does still has the same error message is as follows:

import Lean
open Lean Lean.Meta Lean.Elab Lean.Elab.Tactic Lean.PrettyPrinter

-- TODO: Does not seem to work without
open TSyntax.Compat

set_option pp.rawOnError true

#eval Lean.versionString -- "4.0.0-nightly-2022-07-22"

inductive Even : Nat  Prop
| zero : Even Nat.zero
| add_two :  k : Nat, Even k  Even (k+2)

def x (stx : Syntax): TacticM Unit := do
  evalTactic stx
  match  getUnsolvedGoals with
  | [goal] =>
    let goalStx  delab ( instantiateMVars ( getMVarDecl goal).type)
    let myTacticSeq  `(tactic|$stx; exact this)
    let newStx  `(suffices $goalStx:term by $myTacticSeq:tacticSeq; ?_)
    addTrace `myTactic m!"This message fails with \n{newStx}"
  | _ => logWarning "MWE"

elab &"myTactic " t:tactic : tactic =>
  x t

example : Even 2 := by
  myTactic apply Even.add_two _ _
  -- suffices Even 0 by
  --   apply Even.add_two _ _
  --   exact this
  sorry

With almost the same error:

[myTactic] This message fails with
[Error pretty printing syntax: parenthesize: uncaught backtrack exception. Falling back to raw printer.]
(Term.suffices
 "suffices"
 (Term.sufficesDecl
  []
  (Term.app `Even [(num "0")])
  (Term.byTactic'
   "by"
   (Tactic.seq1
    [(Tactic.apply "apply" (Term.app `Even.add_two [(Term.hole "_") (Term.hole "_")]))
     ";"
     (Tactic.exact "exact" (Lean.termThis "this"))])))
 ";"
 (Term.syntheticHole "?" (Term.hole "_")))

The difference is that I added the TSyntax.Compat open, otherwise $stx is the wrong type. (And seconds before posting I saw that Sebastian Ulrich said on another post that using TSyntax.Compat is a red flag you're doing something wrong :upside_down: )

Additionally, I added ?_ at the end of the suffices block, because the macro definition expects a $body term, even though in my example that is empty. I expect that it now fails because of this last syntheticHole, but I'm unsure on how to figure this out, since I don't really understand why the $body term is mandatory anyways.

Any pointers where I seem to be going wrong?

Sebastian Ullrich (Jul 26 2022 at 10:24):

Ah, you're using term suffices, but I assume you want tactic

elab "myTactic " t:tactic : tactic => do
  evalTactic t
  match  getUnsolvedGoals with
  | [goal] =>
    let goalStx  delab ( instantiateMVars ( getMVarDecl goal).type)
    let newStx  `(tactic| suffices $goalStx:term by $t; exact this)
    addTrace `myTactic m!"This message fails with \n{newStx}"
  | _ => logWarning "MWE"

Reinier van der Gronden (Jul 26 2022 at 10:56):

That certainly makes more sense, however, it still has the error message in your mwe. If you add $t:tactic, it works!

elab "myTactic " t:tactic : tactic => do
  evalTactic t
  match  getUnsolvedGoals with
  | [goal] =>
    let goalStx  delab ( instantiateMVars ( getMVarDecl goal).type)
    let newStx  `(tactic|
      suffices $goalStx:term by
        $t:tactic
        exact this)
    addTrace `myTactic m!"This message succeeds with \n{newStx}"
  | _ => logWarning "MWE"

example : Even 2 := by
  myTactic apply Even.add_two _ _
  sorry

Adds the expected trace:

[myTactic] This message succeeds with
suffices Even 0 by
  apply Even.add_two _ _
  exact this

Thanks for the help, all the different types of terms gets confusing sometimes!

Sebastian Ullrich (Jul 26 2022 at 10:59):

Ah, you need https://github.com/leanprover/lean4-nightly/releases/tag/nightly-2022-07-24 or later for my version

Reinier van der Gronden (Jul 26 2022 at 11:03):

Yes, that works as well. Guess I should keep a bit more of an eye on nightly changes :smile: Thanks again!


Last updated: Dec 20 2023 at 11:08 UTC