Zulip Chat Archive

Stream: mathlib4

Topic: Coercions


Kevin Buzzard (Jan 04 2025 at 18:11):

I have never understood Lean 4 coercions. There are the myriad typeclasses (Coe, CoeTC, CoeOut, CoeOTC, CoeHead, CoeHTC, CoeTail, CoeHTCT, CoeDep, CoeT, many of which are I think implementation details) as well as CoeFun and CoeSort (which I think I do understand) and then also the attribute @[coe] which I think is just for up-arrow notation. I just reviewed a PR on profinite groups and noticed this:

import Mathlib

variable (P : ProfiniteGrp.{0}) -- an object in the category of profinite groups.

#check (P : Type) -- ↑P.toProfinite.toTop : Type

Is that what we want to happen here? It looks a bit ridiculous to me, but I'm not sure that with the current set-up we can just make ↑P : Type be a thing because

instance : CoeSort ProfiniteGrp (Type u) where
  coe G := G.toProfinite

really means coe G := G.toProfinite.toTop.α and in particular there doesn't seem to be a bare function which we can tag with @[coe]. Are we just doomed to have this silly-looking ↑P.toProfinite.toTop in our goals?

Eric Wieser (Jan 04 2025 at 18:43):

It's always possible to write a custom delaborator that prints that specific term as a coercion

Eric Wieser (Jan 04 2025 at 18:43):

@[coe] is nothing more than a mechanism to reuse an existing delaborator in the simple cases

Kevin Buzzard (Jan 04 2025 at 18:45):

Eric Wieser said:

It's always possible to write a custom delaborator that prints that specific term as a coercion

If this delaborator were written for the example above (profinite groups to Type) then it would merely be a syntactic change, thus tidying up printed output, whilst having no affect on mathlib?

Kyle Miller (Jan 04 2025 at 19:06):

Eric Wieser said:

@[coe] is nothing more than a mechanism to reuse an existing delaborator in the simple cases

It's also the mechanism to configure the norm_cast tactics, which @Jireh Loreaux pointed out to me.

Kyle Miller (Jan 04 2025 at 19:09):

If you want a bare function to tag with @[coe], you can make one:

@[coe]
def ProfiniteGrp.toType (G : ProfiniteGrp) : Type u := G

instance : CoeSort ProfiniteGrp (Type u) where
  coe := ProfiniteGrp.toType

I think it's generally better to define coercions using an auxiliary function like this for this reason.

Presumably you'd have a simp lemma to rewrite ↑P.toProfinite.toTop to ↑P.

Jireh Loreaux (Jan 04 2025 at 19:16):

Agreed, I think auxiliary functions are likely the way to go here.

Eric Wieser (Jan 05 2025 at 03:06):

You probably want an abbrev not a def, otherwise you have to copy over all the instances again

Mario Carneiro (Feb 15 2025 at 01:38):

Do we have a linter that all Coe instances are tagged with @[coe]? Should we?

Eric Wieser (Feb 15 2025 at 22:02):

I don't think we should, I think there are cases where you want automatic insertion but you'd prefer to always see the full name in the goal view

Eric Wieser (Feb 15 2025 at 22:03):

But I guess there could be a @[no_coe_pp] attribute, and a linter that ensures either that or @[coe] is present

Mario Carneiro (Feb 16 2025 at 00:35):

I was thinking you would just use @[nolint] when you don't want to use @[coe]


Last updated: May 02 2025 at 03:31 UTC