Zulip Chat Archive

Stream: general

Topic: Synth `OfNat A n` for mvar `A`


Max Nowak ๐Ÿ‰ (Dec 16 2024 at 22:30):

I am making a DSL, and have numeric literals which may be of different type, so I thought I'd use what Lean does and try to synthesize OfNat. My first attempt was:

def elabDsl (A : Q(Type)) : Syntax -> TermElabM Q($A)
| `($n:num) => do
  let n : Nat := n.getNat
  let ofNat <- synthInstance q(OfNat $A $n)
  return q(($ofNat).ofNat)

However, since the expected type A can be unknown, we fail to synthesize the OfNat instance. (It could be Int, BitVec _, etc.). I need to postpone synthesizing OfNat, HAdd, etc until after expected type is known. For this, I found mkInstMVar and used that in place of synthInstance. However, now my instance mvars are never instantiated.

There is probably an idiomatic way of doing this, I just can't find it.

Henrik Bรถving (Dec 16 2024 at 22:33):

Sounds like a good use of tryPostponeIfNoneOrMVar on your expected type to me:

def elab : TermElab := fun stx typ? => do
  tryPostponeIfNoneOrMVar typ?
  let some typ := typ? | throwError "some informative message"

Max Nowak ๐Ÿ‰ (Dec 16 2024 at 22:38):

I'm not sure how to use this. That looks like it just aborts my elaboration altogether if my inst is an mvar? I want my instance to be an mvar, because sometimes I legit don't know the expected type A. I am not sure how to make Lean finish TC synthesis once those mvars are known.

Max Nowak ๐Ÿ‰ (Dec 16 2024 at 22:39):

mkInstMVar sounds like what I want, but it has no documentation and I wasn't able to find much about it here on Zulip.

Kyle Miller (Dec 16 2024 at 22:46):

mkInstMVar is right (and in fact docs#Lean.Elab.Term.elabNumLit uses it for constructing the OfNat instance)

Kyle Miller (Dec 16 2024 at 22:47):

To finish elaboration, you have to either wrap your elaboration routine in withSynthesize or have a synthesizeSyntheticMVarsNoPostponing checkpoint

Max Nowak ๐Ÿ‰ (Dec 16 2024 at 22:50):

Oh wow that did it. Perfect. Awesome. Thanks a ton!

Kyle Miller (Dec 16 2024 at 22:53):

For a mini case study, here's part of the change tactic: https://github.com/leanprover/lean4/blob/master/src/Lean/Elab/Tactic/Change.lean#L21

The runTermElab itself is responsible for doing synthesizeSyntheticMVarsNoPostponing before returns. On line 30, there's a partial checkpoint that allows typeclass problems to be postponed, allowing the isDefEq to try to solve for pending instances.

Then, elaboration is complete, so it's safe to use the next method, which does isDefEq inside a context where synthetic opaque metavariables become assignable. (That let's change assign ?m metavariables for example.)


Last updated: May 02 2025 at 03:31 UTC