Zulip Chat Archive

Stream: lean4

Topic: Checking defeq in Command


Adam Topaz (Sep 07 2023 at 22:08):

I would like to write a command which checks whether two declarations in the current environment have defeq types. It seems, however, that docs#Lean.Meta.isDefEq is in the MetaM monad. Is there some function that does this which can be run in CommandElabM?

Joachim Breitner (Sep 07 2023 at 22:11):

It doesn't get automatically lifted? If not, maybe try liftTermElabM

Adam Topaz (Sep 07 2023 at 22:11):

can you lift from MetaM to CommandElabM?

Scott Morrison (Sep 07 2023 at 22:12):

You could just go all the way to IO with something like:

    let ctx := { fileName, fileMap := default }
    let state := { env := env }
    -- From `IO` to `CoreM`:
    Prod.fst <$> (CoreM.toIO · ctx state) do
        -- From `CoreM` to `MetaM`:
        MetaM.run' (ctx := {}) (s := {}) do

Adam Topaz (Sep 07 2023 at 22:13):

Ok, yes, I was hoping to avoid constructing some empty MetaM context from scratch, but maybe that's the only way?

Henrik Böving (Sep 07 2023 at 22:13):

given the implementation of liftTermElabM https://github.com/leanprover/lean4/blob/a7efe5b60e86b26fefd4795b46d66af369b97329/src/Lean/Elab/Command.lean#L391-L414 and all the additional care taken for macro scopes I don't think that's a good idea

Scott Morrison (Sep 07 2023 at 22:13):

(I had that ready to copy and paste, but presumable you can get there from CommandElabM even more easily.)

Henrik Böving (Sep 07 2023 at 22:13):

why not go joachim's path?

Adam Topaz (Sep 07 2023 at 22:14):

Henrik Böving said:

I don't think that's a good idea

Sorry, what are you referring to here?

Scott Morrison (Sep 07 2023 at 22:14):

liftTermElabM is what you want.

Scott Morrison (Sep 07 2023 at 22:15):

Your MetaM tactic lifts for free to TermElabM, which is even higher up the monad stack, and then liftTermElabM lets you run that from CommandElabM.

Adam Topaz (Sep 07 2023 at 22:15):

Gotcha. I'll try it out. Thanks!

Henrik Böving (Sep 07 2023 at 22:16):

Adam Topaz said:

Henrik Böving said:

I don't think that's a good idea

Sorry, what are you referring to here?

well liftTermElabM goes through a lot of effort to do macro scopes related stuff here while the straight to IO approach just doesn't care about that at all so I would assume you can provoke scenarios where stuff breaks.

Scott Morrison (Sep 07 2023 at 22:17):

I would guess that checking isDefEq on two already elaborated types is fairly safe to do brutally, but why do the guesswork?

Adam Topaz (Sep 07 2023 at 22:18):

Thanks all, liftTermElabM works perfectly fine for my application. Pasting this here in case it helps anyone else in the future:

import Lean

open Lean Elab Meta Command Term

def A : Nat  Nat := sorry
def B : Nat  Nat := sorry
def C : Nat := sorry

#eval show CommandElabM Unit from do
  let env  getEnv
  let some A := env.find? `A | unreachable!
  let some B := env.find? `B | unreachable!
  let some C := env.find? `C | unreachable!
  let A := A.type
  let B := B.type
  let C := C.type
  let b1  liftTermElabM (isDefEq A B)
  let b2  liftTermElabM (isDefEq A C)
  if b1 then IO.println "A and B have the same type"
  if !b2 then IO.println "A and C have different types"

Kyle Miller (Sep 07 2023 at 22:57):

@Adam Topaz There's a small issue with your code, where if you have universe variables then it will require that they have the exact same names.

Adam Topaz (Sep 07 2023 at 22:59):

I think I'm okay with that.

Kyle Miller (Sep 07 2023 at 23:05):

Just to mention it, if you're ok with constants being defeq after some specialization of their universe level parameters, then you could do something like

let b1  liftTermElabM do
  let Aty  inferType ( mkConstWithFreshMVarLevels `A)
  let Bty  inferType ( mkConstWithFreshMVarLevels `B)
  isDefEq Aty Bty

It might be over-specialized though.

Adam Topaz (Sep 07 2023 at 23:29):

Is there any particular reason why we don't have an instance of MonadLiftT MetaM CommandElabM?

Kyle Miller (Sep 07 2023 at 23:36):

I'm not sure you generally want to run MetaM functions with an empty context and no metavariable assignments every time. liftTermElabM (and runTermElabM, which initializes the context with variables) at least delimits where this new context is created.


Last updated: Dec 20 2023 at 11:08 UTC