Zulip Chat Archive
Stream: new members
Topic: Need help converting code from 4.3.0 to 4.26.0
Kevin Cheung (Jan 28 2026 at 18:51):
I'm new to metaprogramming. I am trying to update some code written for 4.3.0 to 4.26.0. Below is the smallest example I could come up with that illustrates my problem:
import Mathlib.Tactic.Linarith
open Lean.Meta Qq Mathlib.Meta.NormNum
def foo (n : ℤ) : Prop := n = 2
@[norm_num foo _ ] def evalFoo : NormNumExt where eval (e : Q(Prop)) := do
let .app f (n : Q(ℤ)) ← whnfR e | failure
guard <|← withNewMCtxDepth <| isDefEq f q(foo)
let rn : Result n ← derive n
let i : Q(Ring ℤ) := q(Int.instRingInt)
let ⟨zn, _, _⟩ ← rn.toInt
sorry
Lean 4.3.0 was happy with the above, just highlighting the sorry as a warning.
My attempt to make it work in 4.26.0 first made me change Int.instRingInt to Int.instRing:
import Mathlib.Tactic.Linarith
open Lean.Meta Qq Mathlib.Meta.NormNum
def foo (n : ℤ) : Prop := n = 2
@[norm_num foo _ ] def evalFoo : NormNumExt where eval (e : Q(Prop)) := do
let .app f (n : Q(ℤ)) ← whnfR e | failure
guard <|← withNewMCtxDepth <| isDefEq f q(foo)
let rn : Result n ← derive n
let i : Q(Ring ℤ) := q(Int.instRing)
let ⟨zn, _, _⟩ ← rn.toInt
sorry
However, Lean 4.26.0 now gives an error right before sorry:
Type mismatch
Result.toInt ?m.60 rn
has type
Option (ℤ × (lit : Q(ℤ)) × Q(IsInt «$n» «$lit»))
but is expected to have type
MetaM ?m.56
I cannot figure out what is wrong since the error is not present in the 4.3.0 version. Help greatly appreciated.
Aaron Liu (Jan 28 2026 at 19:02):
Do you understand what the error message is saying?
Kevin Cheung (Jan 28 2026 at 19:03):
I know there is a type mismatch. toInt is returning something that is not MetaM something.
Kevin Cheung (Jan 28 2026 at 19:03):
Otherwise, I'm baffled because I don't understand how the code could possibly work in 4.3.0.
Aaron Liu (Jan 28 2026 at 19:04):
Do you know what MetaM is?
Kevin Cheung (Jan 28 2026 at 19:04):
Only vaguely. It's a monad.
Aaron Liu (Jan 28 2026 at 19:06):
let ⟨zn, _, _⟩ ← rn.toInt
In this snippet I can see that you are pulling out three elements from rn.toInt, which should be returning a monadic computation since we have the ← which means to run a monadic computation.
Kevin Cheung (Jan 28 2026 at 19:07):
Right. But somehow that was legal in 4.3.0.
Aaron Liu (Jan 28 2026 at 19:08):
From the error message I can see the actual type of rn.toInt is
Option (ℤ × (lit : Q(ℤ)) × Q(IsInt «$n» «$lit»))
Aaron Liu (Jan 28 2026 at 19:08):
so there are still three values in there, but they are not behind a monadic computation anymore
Aaron Liu (Jan 28 2026 at 19:08):
instead, it's just an Option
Kevin Cheung (Jan 28 2026 at 19:08):
I just tried Gemini. It suggests let some ⟨zn, _, _⟩ := rn.toInt | failure
Aaron Liu (Jan 28 2026 at 19:09):
yes, that's what I would have suggested too
Kevin Cheung (Jan 28 2026 at 19:09):
So 4.3.0 must be doing something weird.
Aaron Liu (Jan 28 2026 at 19:10):
so probably what happened is that at some point the function was changed from being monadic to returning an Option value
Aaron Liu (Jan 28 2026 at 19:11):
and the reason your old code failed is because you are still using ← with your let which means "run this monadic computation and get the value out"
Aaron Liu (Jan 28 2026 at 19:11):
and that failed because rn.toInt isn't a monadic computation anymore
Kevin Cheung (Jan 28 2026 at 19:11):
I see.
Kevin Cheung (Jan 28 2026 at 19:12):
This is what I found in the old code:
def Result.toInt {α : Q(Type u)} {e : Q($α)} (_i : Q(Ring $α) := by with_reducible assumption) :
Result e → Option (ℤ × (lit : Q(ℤ)) × Q(IsInt $e $lit))
Kevin Cheung (Jan 28 2026 at 19:12):
Doesn't seem monadic here.
Aaron Liu (Jan 28 2026 at 19:13):
then, I guess the other option is that there could've been a coercion to interpret a value of type Option as a MetaM computation, and this coercion was turned off
Kevin Cheung (Jan 28 2026 at 19:14):
I see. In any case, looks like my problem is solved. With the change, things seem to work now. Thanks.
Last updated: Feb 28 2026 at 14:05 UTC