Zulip Chat Archive
Stream: std4
Topic: Problem with `repeat'`
Scott Morrison (Oct 19 2023 at 07:42):
I'm having a problem with repeat'
. Here's the smallest minimisation I have so far:
import Std.Tactic.Basic
open Lean Elab Tactic Meta
def Lean.MVarId.assignFresh (mvarId : MVarId) : MetaM MVarId := do
let mvarIdNew ← mkFreshExprMVar (← mvarId.getType)
mvarId.assign mvarIdNew
return mvarIdNew.mvarId!
elab "foo" : tactic => liftMetaTactic fun g => do _ ← g.assignFresh; throwError ""
example : False := by -- (kernel) declaration has metavariables '_example'
repeat' foo
Scott Morrison (Oct 19 2023 at 07:43):
This also happens with g.assignFresh
replaced by g.exFalso
.
Scott Morrison (Oct 19 2023 at 07:43):
This is minimised from the even shorter:
import Mathlib.Tactic.Linarith
example : False := by -- (kernel) declaration has metavariables '_example'
repeat' linarith
Scott Morrison (Oct 19 2023 at 07:43):
@Mario Carneiro, do you see what is wrong here? I think it must be repeat'
s fault.
Mario Carneiro (Oct 19 2023 at 07:52):
Your foo
is breaking the contract that repeat'
expects. Specifically, if you throw an exception, then repeat'
will put the original goal back on the goal list, so it should not be assigned. If it is assigned then it will be pruned from the list, so in this example that means that mvarIdNew
is dropped on the floor and you have an empty goal list even though there are metavariables remaining
Scott Morrison (Oct 19 2023 at 07:53):
Would it be okay to change repeat'
so it rewinds the MetavarContext
on an exception?
Scott Morrison (Oct 19 2023 at 07:54):
This seems like a nasty footgun (as evidenced by the repeat' linarith
example).
Mario Carneiro (Oct 19 2023 at 07:54):
is it something that can be fixed in linarith
?
Scott Morrison (Oct 19 2023 at 07:55):
But... but... where is the contract that says that failing tactics are responsible for rewinding all of their state? That's not a universal expectation, is it?
Scott Morrison (Oct 19 2023 at 07:55):
I thought this was unreasonable expectations on the part of repeat'
, not bad behaviour on the part of linarith
.
Mario Carneiro (Oct 19 2023 at 07:56):
repeat'
essentially uses a try catch
block to catch exceptions in the inner function. This does not rewind the state by default
Mario Carneiro (Oct 19 2023 at 07:56):
it is not clear to me if rewinding the state is desirable in general
Scott Morrison (Oct 19 2023 at 07:58):
I'm worried that we have lots of tactics out there that error without rewinding the state, and repeat'
is not going to be usable with any othem.
Mario Carneiro (Oct 19 2023 at 07:59):
fixed (I had to change observing
to observing?
... it is not good that such similarly sounding functions have this different behavior)
Mario Carneiro (Oct 19 2023 at 08:08):
Scott Morrison (Oct 19 2023 at 08:14):
Okay, and #7769 is the matching mathlib PR that makes sure linarith
rolls back the state as well. Defence in depth!
Last updated: Dec 20 2023 at 11:08 UTC