Zulip Chat Archive

Stream: Is there code for X?

Topic: MessageData.ofPPFormat


Joachim Breitner (Apr 09 2024 at 06:36):

It seems that ofPPFormat can be used to create a MessageData „lazily“. I expect this would be very useful in tactic code of the form

throwError m!"foo bar {← baz}"

where baz : MetaM MessageData is a possibly expensive operation, and you don’t want to run it unless someone really looks at the message, so that try tac will not spend time assembling the error message.

But I don’t quite understand the plumbing here. Can one write a

lazyMessageData : MetaM MessageData  MessageData

or

lazyMessageData : MetaM MessageData  MetaM MessageData

somehow?

Joachim Breitner (Apr 09 2024 at 08:26):

Here is a first attempt, although I expect it loses the ability to hover…

def _root_.Lean.MessageData.thunk (f : Unit  MessageData) : MessageData :=
  .ofPPFormat <| { pp := fun
    | .some ppctx => do
      let msg := f ()
      msg.formatAux
        {currNamespace := ppctx.currNamespace, openDecls := ppctx.openDecls}
        (some {env := ppctx.env, mctx := ppctx.mctx, lctx := ppctx.lctx, opts := ppctx.opts})
    | .none => do
      let msg := f ()
      msg.format}

It seems hard to use ofPPformat for this without losing the info hover.

Let’s try adding a constructor .thunk : Thunk MessageData → MessageData… that works ok if the delayed code is pure, until you need to do MetaM stuff lazily, thenThunk is too restrictive, but .thunk : IO MessageData → MessageData fails inductive can’t recurse through IO, it seems… oh wey.

𝚠𝚘𝚓𝚌𝚒𝚎𝚌𝚑 𝚗𝚊𝚠𝚛𝚘𝚌𝚔𝚒 (Apr 09 2024 at 22:44):

Here is my attempt:

import Lean
open Lean Elab Meta Term Command

def lazyMessageData (mx : MetaM MessageData) : MetaM MessageData := do
  let metaCtx  readThe Meta.Context
  let metaSt  getThe Meta.State
  let coreCtx  readThe Core.Context
  let coreSt  getThe Core.State
  let m := MessageData.ofPPFormat {
    pp := fun _ => do
      let (m, _) 
        (mx >>= addMessageContextFull)
          |>.run' metaCtx metaSt
          |>.toIO coreCtx coreSt
      MessageData.format m
    }
  return m

elab "#test" t:term : command => do
  Command.liftTermElabM do
    let t  elabTerm t none
    let m  lazyMessageData (return m!"lazy: {t}")
    logInfo m
    logInfo m!"eager: {t}"


#test 42

You are right that it loses hovers. I am not entirely sure, but I'd say this is a bug. Perhaps in msgToInteractiveAux?

Eric Wieser (Apr 09 2024 at 23:45):

Is this "save all the state for a callback" what docs#control is for?

Joachim Breitner (Apr 10 2024 at 06:58):

Thanks @Wojciech Nawrocki! I am playing around with something similar in https://github.com/leanprover/lean4/pull/3234 now.

@Eric Wieser I thought so, but couldn't get it to work. Maybe we don’t have the necessary instances to go from MetaM to IO?


Last updated: May 02 2025 at 03:31 UTC