Zulip Chat Archive
Stream: new members
Topic: structure: field vs. parameter
Yannick Seurin (Dec 09 2025 at 11:01):
When defining a structure that depends on some type α, one can declare it either as a parameter or a field. Say I want to do something like this (which works well):
import Mathlib
noncomputable section
structure Foo (α : Type) where
draw_random : PMF α
variable (G : Type) [CommGroup G] [Fintype G]
def bar : Foo G where
draw_random := PMF.uniformOfFintype G
def mul_by_const (a : G) : PMF G := do
let x ← (bar G).draw_random
PMF.pure (a * x)
end
But if I try to declare α as a field, then I run into the following problem:
import Mathlib
noncomputable section
structure Foo where
α : Type
draw_random : PMF α
variable (G : Type) [CommGroup G] [Fintype G]
def bar : Foo where
α := G
draw_random := PMF.uniformOfFintype G
def mul_by_const (a : G) : PMF G := do
let x ← (bar G).draw_random
PMF.pure (a * x) -- failed to synthesize HMul G (bar G).α ?m.14
end
Is there a way to have Lean realize that (bar G).α is actually G?
As a side question, when should one prefer the field vs. parameter approach? MIL briefly touches the question in Section7.2:
It is sometimes useful to bundle the type together with the structure, and Mathlib also contains a definition of a
Grpstructure that is equivalent to the following:structure Grp₁ where
α : Type*
str : Group₁ αThe Mathlib version is found in
Mathlib.Algebra.Category.Grp.Basic, and you can#checkit if you add this to the imports at the beginning of the examples file.For reasons that will become clearer below, it is more often useful to keep the type
αseparate from the structureGroup α.
The parameter approach seems to facilitate class inference, are there other benefits? When is the field approach preferable?
Snir Broshi (Dec 09 2025 at 20:12):
Is there a way to have Lean realize that
(bar G).αis actuallyG?
let x : G ← (bar G).draw_random
Also in general you should use Type* rather than Type, like the MIL example you quoted, unless you have a good reason to not be generic over universes
Snir Broshi (Dec 09 2025 at 20:18):
The approaches you describe are bundled vs unbundled. I think the field version is the bundled one.
The field approach with Types isn't that useful AFAIK, but with other things it is.
For example, graphs over vertices V : Type* currently have a type Walk (u v : V) where u v are the endpoints specified as parameters, but this makes it hard to compare walks with different endpoints.
There's also docs#SimpleGraph which has the parameter V : Type*, whereas docs#Graph has such a parameter but also a field vertexSet : Set V which makes it easier to work with graphs over a different set of vertices.
You can also read #mathlib4 > The design of matroids which I believe talks about similar problems.
Yannick Seurin (Dec 10 2025 at 09:52):
Thanks a lot for the pointers!
Last updated: Dec 20 2025 at 21:32 UTC