Zulip Chat Archive

Stream: mathlib4

Topic: Writing a delaborator for WithLp.toLp


Etienne Marion (Oct 19 2025 at 06:22):

Hi! In #27270 I turn WithLp into a one field structure with two constructors, one of which being WithLp.toLp. The issue is that when writing WithLp.toLp p x in the code, it gets printed as { ofLp := x } which is not great for readability (and causes the build error in the PR in some testing file). Jireh suggested that we would just need a delaborator to fix the issue. Here comes the tricky part: I have absolutely no idea how meta programming works and find the syntax very obscure. Taking inspiration on the delaborator for the !₂[x, y, ...] notation in Analysis.InnerProductSpace.PiL2 I wrote the following:

import Mathlib

open Lean Meta Elab Term Macro TSyntax PrettyPrinter.Delaborator SubExpr

@[app_delab WithLp.toLp]
def test : Delab :=
  whenNotPPOption getPPExplicit <| whenPPOption getPPNotation <| withOverApp 3 do
    -- check that the `WithLp.toLp _` is present
    let p : Term  withNaryArg 0 <| delab
    let x  withNaryArg 2 delab
    `(toLp $p $x)

variable (p : ENNReal)

#check WithLp.toLp p (0 : ) -- toLp✝ p 0 : WithLp p ℝ

which kinda works but prints out toLp✝ instead of just toLp. I don't know where to find instructions so I have no idea what to do to solve the issue or if what I wrote is the right way to do it. It looks like the issue comes from the fact that I want to print an existing function. Any help would be greatly appreciated!

Eric Wieser (Oct 19 2025 at 09:08):

You should use withNaryFun delab to get the toLp part

Eric Wieser (Oct 19 2025 at 09:08):

Though I think there might be a pp setting to disable constructor notation that could help here

Eric Wieser (Oct 19 2025 at 09:09):

(and we should probably build this for ULift.up too)

Etienne Marion (Oct 19 2025 at 13:37):

It looks like

set_option pp.structureInstances false

solves it, but I don't think we want this across all mathlib. Can it be activated only for toLp?

Etienne Marion (Oct 19 2025 at 13:40):

Ok this seems to work!

import Mathlib

open Lean Meta Elab Term Macro TSyntax PrettyPrinter.Delaborator SubExpr

@[app_delab WithLp.toLp]
def test : Delab :=
  whenNotPPOption getPPExplicit <| whenPPOption getPPNotation <| withOverApp 3 do
    let toLp  withNaryFn delab
    let p  withNaryArg 0 delab
    let x  withNaryArg 2 delab
    `($toLp $p $x)

variable (p : ENNReal)

#check WithLp.toLp p (0 : ) -- WithLp.toLp p 0 : WithLp p ℝ

Etienne Marion (Oct 19 2025 at 13:45):

Yes the error in the testing file is fixed, thanks Eric!

Eric Wieser (Oct 19 2025 at 13:55):

This also works:

@[app_delab WithLp.toLp]
def test : Delab := delabApp

Etienne Marion (Oct 19 2025 at 13:59):

lol, well that was easy

Eric Wieser (Oct 19 2025 at 14:02):

I was going to suggest that you can set the pp.structureInstances option locally in the elaborator then fall back to the default delaborator, then realized that the default delaborator already does the right thing.

Eric Wieser (Oct 19 2025 at 14:03):

(If you just call delab then Lean goes into a loop and prints an ellipsis)

Etienne Marion (Oct 19 2025 at 14:06):

So delabApp is the "Default delaborator for applications" (according to the docstring), but here because toLp is a constructor there is a kind of conflict and it's another delaborator which is used?

Eric Wieser (Oct 19 2025 at 14:07):

Yes, as there are multiple things registered with @[delab app], and they are tried in order

Eric Wieser (Oct 19 2025 at 14:10):

I guess this is the other way to write it without referring to a handler by name:

@[app_delab WithLp.toLp]
def test : Delab :=
  whenPPOption pp.structureInstances.get do
    withOptions (pp.structureInstances.set · false) do
      delab

though this isn't quite correct as it disables the option for x too.


Last updated: Dec 20 2025 at 21:32 UTC