Zulip Chat Archive

Stream: metaprogramming / tactics

Topic: Renaming existing fields in structure?


Quang Dao (Oct 22 2025 at 16:36):

@Devon Tuma and I are building VCVio, which defines an oracle computation framework that is equal to taking the free monad over a polynomial functor (seen as a (dependent) oracle). Specifically, our stack is:

import Mathlib.Data.PFunctor.Univariate.Basic

universe uA uB u v

/-- Alias the base functor. -/
abbrev OracleSpec := PFunctor.{uA,uB}

namespace OracleSpec
/-- Pretty names for `PFunctor.A`/`PFunctor.B`. -/
abbrev Domain (spec : OracleSpec) : Type uA := spec.A
abbrev Range (spec : OracleSpec) (t : spec.Domain) : Type uB := spec.B t
end OracleSpec

inductive FreeM (P : PFunctor.{uA,uB}) : Type u  Type (max uA uB u)
  | pure {α : Type u} (x : α) : FreeM P α
  | roll {α : Type u} (a : P.A) (k : P.B a  FreeM P α) : FreeM P α

/-- Query object is the polynomial functor object. -/
abbrev OracleQuery (spec : OracleSpec.{uA,uB}) : Type u  Type (max uA uB u) :=
  PFunctor.Obj spec

/-- Syntactic query (same as `⟨t, id⟩`). -/
def query {spec : OracleSpec} (t : spec.Domain) : OracleQuery spec (spec.Range t) :=
  t, id

/-- Computations are the free monad over the spec. -/
abbrev OracleComp (spec : OracleSpec.{uA,uB}) : Type u  Type (max uA uB u) :=
  FreeM spec

My question is: is it possible to show .Domain and .Range in the infoview instead of the default names .A and .B in PFunctor? Similarly, print out PFunctor.Obj as OracleQuery and PFunctor.FreeM as OracleComp?

Matej Penciak (Oct 25 2025 at 03:49):

I'm not sure this is the most principled way of doing it, but this works:

import Lean

structure Foo where
  a : Type
  b : a

open Lean Meta PrettyPrinter Delaborator SubExpr

@[app_delab Foo.a]
def delabFooA : Delab := do
  let expr  getExpr
  let_expr Foo.a body := expr | throwError ":("
  return  `($(delab body).$(mkIdent `newName))

@[app_delab Foo.b]
def delabFooB : Delab := do
  let expr  getExpr
  let_expr Foo.b body := expr | throwError ":("
  return  `($(delab body).$(mkIdent `otherNewName))

example (x y : Foo) (h : x.a = y.a) : x.b = h  y.b := by
  -- x y : Foo
  -- h : x.newName = y.newName
  -- ⊢ x.otherNewName = ⋯ ▸ y.otherNewName
  sorry

It feels a bit like a hack though, and there are a bunch of edge cases you'd need to deal with in the delaborator to get the behavior everywhere

Eric Wieser (Oct 25 2025 at 11:27):

What advantage does PFunctor provide here vs directly passing around the index types {ι : Type*} {ω : ι → Type*}?

Eric Wieser (Oct 25 2025 at 11:29):

(for instance, docs#Std.DHashMap and docs#DFinsupp could take a PFunctor as input, but they do not)

Eric Wieser (Oct 25 2025 at 11:30):

Putting types into structures is generally a way to end up in a fight with Lean's typeclass resolution

Devon Tuma (Oct 25 2025 at 16:32):

I guess the current reason would be that the dependent omega type can get complicated quite quickly, even just adding a few PFunctor together gives multiple eliminator calls in it. This seemed to get fairly messy in my experience, especially in reductions where you modify the oracle spec multiple times.

We did at one time have both an indexing type being passed around and also a domain type in the struct, but combined the indexing into the domain in the struct (giving essentiallyPFunctor). Maybe it would be better to instead move the domain out of the struct into the indexing being passed around.

Type class resolution errors have come up but they generally seem to have been handled by marking structs as reducible, at least for now

Eric Wieser (Oct 27 2025 at 11:35):

I guess once you get to eliminator calls you run into trouble with typeclass inference anyway


Last updated: Dec 20 2025 at 21:32 UTC