Zulip Chat Archive
Stream: lean4
Topic: Diamond in MonadExcept
Adam Topaz (Apr 16 2025 at 15:54):
I came across a diamond in core for MonadExcept Exception TacticM
. I'm happy to work around it in my current application, and i don't expect anything to be done, but I just wanted to make sure that this is mentioned somewhere.
import Lean
open Lean Elab Tactic
example :
(inferInstance : MonadExcept Exception TacticM) =
(instMonadExceptOfMonadExceptOf Exception TacticM) :=
rfl -- Fails
Adam Topaz (Apr 16 2025 at 15:55):
I came across this because I had some functions that assumed MonadExcept E M
, and a function later on that assumed MonadError M
. Now, MonadError M
implies MonadExceptOf Exception M
which implies MonadExcept Exception M
, so I ended up with two nondefeq instances when I tried to apply things to M = TacticM
.
Eric Wieser (Apr 16 2025 at 16:19):
Concerningly this means you can get the wrong catch
behavior:
import Lean
open Lean Elab Tactic
example :
(inferInstance : MonadExcept Exception TacticM) =
(instMonadExceptOfMonadExceptOf Exception TacticM) := by
dsimp [instMonadExceptOfMonadExceptOf, inferInstance, instMonadExceptExceptionTacticM, throwThe, throw, tryCatchThe]
congr
rfl -- Fails
Eric Wieser (Apr 16 2025 at 16:25):
A lot of annoying unfolding gets you to
import Lean
open Lean Elab Tactic
example :
(inferInstance : MonadExcept Exception TacticM) =
(instMonadExceptOfMonadExceptOf Exception TacticM) := by
dsimp [instMonadExceptOfMonadExceptOf, inferInstance, instMonadExceptExceptionTacticM, ReaderT.instMonadExceptOf, throwThe, throw, tryCatchThe,
StateRefT'.instMonadExceptOf, instMonadLiftTOfMonadLift, ReaderT.instMonadLift, liftM, tryCatchThe]
unfold tryCatchThe
dsimp [instMonadExceptOfExceptionCoreM, Tactic.tryCatchRestore]
unfold Tactic.tryCatchRestore instMonadExceptOfMonadExceptOf ReaderT.instMonadExceptOf tryCatchThe StateRefT'.instMonadExceptOf
dsimp [instMonadExceptOfExceptionCoreM, Tactic.tryCatchRestore]
unfold tryCatchThe
dsimp [instMonadExceptOfExceptionCoreM, Tactic.tryCatchRestore]
/--
⊢ { throw := fun {α} => throwThe Exception,
tryCatch := fun {α} x h => do
let b ← saveState
fun r s r_1 s_1 r_2 s_2 =>
Core.tryCatch (x r s r_1 s_1 r_2 s_2) fun e => (b.restore >>= fun x => h e) r s r_1 s_1 r_2 s_2 } =
{ throw := fun {α} => throwThe Exception,
tryCatch := fun {α} x handle r s r_1 s_1 r_2 s_2 =>
Core.tryCatch (x r s r_1 s_1 r_2 s_2) fun e => handle e r s r_1 s_1 r_2 s_2 }
-/
Eric Wieser (Apr 16 2025 at 16:26):
So if you write [MonadExcept Exception m]
then catch
means "restore the state on failure", but if you write [MonadExceptOf Exception m]
then it doesn't
Last updated: May 02 2025 at 03:31 UTC