Zulip Chat Archive

Stream: lean4

Topic: missing `CoeFun` instance for `SubType`


Jovan Gerbscheid (Jul 13 2025 at 16:35):

I would have expected the following to work:

example (x : {f : Nat  Nat // f 3 = 2}) : Nat  Nat :=
  fun n => x n

It works when writing x instead of fun n => x n. Is this intended behaviour? There are quite a few instances in mathlib that are special cases of the above missing instance.

Aaron Liu (Jul 13 2025 at 16:37):

this seems normal to me

Jovan Gerbscheid (Jul 13 2025 at 16:39):

You don't think that it would make sense for all coercions to a function to be synthesized by CoeFun?

Aaron Liu (Jul 13 2025 at 16:40):

I don't think that would make sense

Aaron Liu (Jul 13 2025 at 16:40):

I think CoeFun is for when a term in an application position is not a function

Jovan Gerbscheid (Jul 13 2025 at 16:41):

Yes, x : {f : Nat → Nat // f 3 = 2} is not a function. And I know it has a coercion to a function, so I'd want it to get picked up by CoeFun.

Aaron Liu (Jul 13 2025 at 16:42):

interesting take

Aaron Liu (Jul 13 2025 at 16:43):

it won't get pretty-printed as a coefun though

Aaron Liu (Jul 13 2025 at 16:44):

import Mathlib

def test (x : {f : Nat  Nat // f 3 = 2}) : Nat  Nat :=
  fun n => (x : Nat  Nat) n

/--
info: def test : { f // f 3 = 2 } → ℕ → ℕ :=
fun x n => ↑x n
-/
#guard_msgs in
#print test

Eric Wieser (Jul 13 2025 at 16:44):

I think that's a feature

Eric Wieser (Jul 13 2025 at 16:44):

We don't want two spellings of the same thing in the infoview

Aaron Liu (Jul 13 2025 at 16:44):

yes and that's why I think it shouldn't be a coefun

Eric Wieser (Jul 13 2025 at 16:45):

That's why it shouldn't be a DFunLike

Aaron Liu (Jul 13 2025 at 16:46):

then you would have to deal with Subtype.val _ and DFunLike.coe _ being two different spellings of the same thing

Aaron Liu (Jul 13 2025 at 16:46):

that would be bad

Aaron Liu (Jul 13 2025 at 16:46):

so definitely not DFunLike

Aaron Liu (Jul 13 2025 at 16:46):

but maybe we could register Subtype.val as a CoeFun instance I think is the issue being brought up here

Eric Wieser (Jul 13 2025 at 16:47):

I think that

instance {p : (α  β)  Prop} : CoeFun (Subtype p) (fun _ => α  β) where
  coe := Subtype.val

is relatively harmless, and that the primary reason it doesn't exist is that in lean 3 it would have behaved as DFunLike does now

Eric Wieser (Jul 13 2025 at 16:48):

Or even

instance {X f} {p : X  Prop} [CoeFun X f] : CoeFun (Subtype p) (fun p => f p.1) where
  coe x := CoeFun.coe x.val

Jovan Gerbscheid (Jul 13 2025 at 16:53):

Yes I think the second option is better

instance {X f} {p : X  Prop} [CoeFun X f] : CoeFun (Subtype p) (fun x => f x.val) where
  coe x := CoeFun.coe x.val

(avoiding repeating variable p)

Jovan Gerbscheid (Jul 13 2025 at 17:00):

Should I try to add this to core, or for now to Mathlib.Data.Subtype?

Eric Wieser (Jul 13 2025 at 17:23):

I think probably core

Eric Wieser (Jul 13 2025 at 17:24):

Either this is a good idea for everyone or it isn't, this doesn't seem mathlib specific

Jovan Gerbscheid (Jul 13 2025 at 17:30):

A slight annoyance here is that

`CoeFun` instances apply to `CoeOut` as well.

So, adding this instance means that there are now two different CoeOut instances for Subtype.

Eric Wieser (Jul 13 2025 at 17:31):

Are they likely to actually be different?

Jovan Gerbscheid (Jul 13 2025 at 17:33):

I was saying it more out of efficiency considerations

Jovan Gerbscheid (Jul 13 2025 at 17:39):

I wonder if there is any reason why we can't define CoeFunT as the transitive closure of CoeOut, and generate that instead of CoeFun. Then it would just need to check that the generated type is indeed a function. Currently if it generates a non-function type, it says:

failed to coerce
  x
to a function, after applying `CoeFun.coe`, result is still not a function
  x.bla
this is often due to incorrect `CoeFun` instances, the synthesized instance was
  instCoeFunMyFun'MyFun

Edward van de Meent (Jul 14 2025 at 13:10):

i imagine because CoeFunT will then include lots of instances which will not at all be conducive in creating a function?

Jovan Gerbscheid (Jul 14 2025 at 13:12):

Yeah. I thought at first that there wouldn't be other CoeOut instances for function-like types. But they do exists, for example

instance coeOutMonoidHom : CoeOut (A →ₐ[R] B) (A →* B)

Jireh Loreaux (Jul 14 2025 at 13:25):

Eric Wieser said:

instance {X f} {p : X  Prop} [CoeFun X f] : CoeFun (Subtype p) (fun p => f p.1) where
  coe x := CoeFun.coe x.val

You're proposing adding both the above and also this:

Eric Wieser said:

instance {p : (α  β)  Prop} : CoeFun (Subtype p) (fun _ => α  β) where
  coe := Subtype.val

right? Because the first one doesn't imply the second, unless I'm grossly mistaken.

Jovan Gerbscheid (Jul 14 2025 at 13:32):

Note that the docstring of CoeFun.coe is also confused about the non-transitive nature of CoeFun

/-- Coerces a value `f : α` to type `γ f`, which should be either be a
  function type or another `CoeFun` type, in order to resolve a mistyped
  application `f x`. -/

But if I try to have γ f be another CoeFun type, I get an error:

structure A where
  a : Nat  Nat

structure B where
  b : A

instance : CoeFun A (fun _ => Nat  Nat) := A.a
instance : CoeFun B (fun _ => A) := B.b

variable (x : B) (n : Nat)

#check x n -- error

Jovan Gerbscheid (Jul 14 2025 at 16:31):

Another option is to add this instance to Mathlib:

instance {F α β} {p : F  Prop} [DFunLike F α β] : DFunLike (Subtype p) α β where
  coe x := DFunLike.coe x.val
  coe_injective' _ _ h := Subtype.ext (DFunLike.coe_injective' h)

I've started trying this at #27143

Aaron Liu (Jul 14 2025 at 16:36):

Doesn't that not fix the original issue, since functions aren't funlike?

Jovan Gerbscheid (Jul 14 2025 at 16:37):

You're right. I think I'll then also add an instance to make functions be funlike

Jireh Loreaux (Jul 14 2025 at 16:56):

No, please don't.

Jovan Gerbscheid (Jul 14 2025 at 16:58):

What is the disadvantage of an instance of DFunLike (∀ a, β a) α β?

Yaël Dillies (Jul 14 2025 at 17:29):

It has absolutely awful performance

Jovan Gerbscheid (Jul 14 2025 at 17:31):

Really? I though DFunLike F _ _ goals in type class search usually arise when F is NOT a function. So a DFunLike (∀ a, β a) α β instance would essentially do nothing performance wise.

Jovan Gerbscheid (Jul 14 2025 at 17:31):

Anyways, it turns out my idea doesn't work, because it gives an application of DFunLike.coe instead of Subtype.val.


Last updated: Dec 20 2025 at 21:32 UTC