Zulip Chat Archive

Stream: lean4

Topic: How to read a private definition


Mario Carneiro (May 31 2021 at 20:33):

Recently Jeremy asked me what the automatically generated definition for this type was. It turned out to be harder than anticipated to find out.

import Lean

inductive FOTerm
  | var : String  FOTerm
  | app : String  List FOTerm  FOTerm
  deriving BEq

#synth BEq FOTerm -- instBEqFOTerm

#print instBEqFOTerm
-- def instBEqFOTerm : BEq FOTerm :=
-- { beq := [anonymous] }

-- ..what?

section
set_option pp.all true
#print instBEqFOTerm
end

-- def instBEqFOTerm : BEq.{0} FOTerm :=
-- @BEq.mk.{0} FOTerm _private.0.beqFOTerm✝

#print _private.0.beqFOTerm -- syntax fail

open Lean Elab Term Eval

#eval show TermElabM Unit from do
  let env  getEnv
  logInfo ( env.find? `instBEqFOTerm).get!.value!.appArg!.constName!
-- _private.0.beqFOTerm._@._hyg.2488

#print _private.0.beqFOTerm._@._hyg.2488 -- more syntax fail

#eval show TermElabM Unit from do
  let env  getEnv
  let n := ( env.find? `instBEqFOTerm).get!.value!.appArg!.constName!
  logInfo ( env.find? n).get!.value!
-- #0

-- The definition has no value?

#eval show TermElabM Unit from do
  let env  getEnv
  let n := ( env.find? `instBEqFOTerm).get!.value!.appArg!.constName!
  let ConstantInfo.opaqueInfo d  ( env.find? n).get! | panic! ""

-- it's opaque.. because it's a partial def
-- The actual definition isn't there, it's in an implementedBy that the compiler generated

#eval show TermElabM Unit from do
  let env  getEnv
  let ci := Compiler.mkUnsafeRecName ( env.find? `instBEqFOTerm).get!.value!.appArg!.constName!
  let e := ( env.find? ci).get!.value!
  logInfo e

-- fun (x x_1 : FOTerm) =>
--   let localinst : BEq FOTerm := { beq := _unsafe_rec };
--   match x, x_1 with
--   | FOTerm.var a, FOTerm.var b => true && a == b
--   | FOTerm.app a a_1, FOTerm.app b b_1 => true && a == b && a_1 == b_1
--   | x, x_2 => false

-- success!

Gabriel Ebner (May 31 2021 at 20:36):

Do we need a sudo #print?

Daniel Fabian (May 31 2021 at 20:39):

I vote for #print_dammit :P

Sebastian Ullrich (May 31 2021 at 20:41):

Maybe not the answer you wanted, but I always use tracing instead of #printing a helper definition after the fact.

set_option trace.Elab.command true

Doesn't work from a different file of course.

Mario Carneiro (May 31 2021 at 20:42):

I think this story would have ended better if the name of the definition generated by the deriving instance was instBEqFOTerm.impl instead of _private.0.beqFOTerm._@._hyg.2488. Then I could have just written #print instBEqFOTerm.impl._unsafe_rec

Mario Carneiro (May 31 2021 at 20:45):

Here's the version pulled from trace.Elab.command:

[Elab.command] mutual
  set_option match.ignoreUnusedAlts true
  private partial def beqFOTerm (x : @FOTerm) (x✝¹ : @FOTerm) : Bool :=
    let localinst : BEq (@FOTerm) := beqFOTerm;
    match x, x✝¹ with
    | @FOTerm.var a, @FOTerm.var b => true && a == b
    | @FOTerm.app a✝¹ a✝², @FOTerm.app b✝¹ b✝² => true && a✝¹ == b✝¹ && a✝² == b✝²
    | _, _ => false
end

It's private and hygienic. That's like double private

Mario Carneiro (May 31 2021 at 20:47):

apparently there's even a hygienic set_option option?

Mario Carneiro (May 31 2021 at 20:47):

wait, even Bool✝ has a tombstone, that looks fishy

Sebastian Ullrich (May 31 2021 at 20:54):

This is before elaboration, so there is no telling whether Bool will be a global reference

Sebastian Ullrich (May 31 2021 at 20:56):

And yes, all idents in a quotation are hygiened. The set_option elaborator will remove the scopes again.


Last updated: Dec 20 2023 at 11:08 UTC