Zulip Chat Archive
Stream: mathlib4
Topic: Coercions in Mathlib4 vs Mathlib3
Oliver Nash (Feb 21 2023 at 16:03):
Looking at the porting PR https://github.com/leanprover-community/mathlib4/pull/2262 opened by @Lukas Miaskiwskyi I see some surprising (to me) warnings from the dangerousInstance
linter.
It looks like in Mathlib4 an instance of Coe A B
is "dangerous" if B
drops some carrier types that were present in A
. I'll illustrate this slightly vague statement with the following pair of MWEs.
Oliver Nash (Feb 21 2023 at 16:04):
First the Lean 3 version:
import tactic.default
variables (X Y : Type*)
class foo := (x : X)
structure bar [foo X] :=
(to_fun : X → X)
(to_fun_x : to_fun foo.x = foo.x)
structure baz [foo X] [foo Y] extends bar X :=
(to_fun' : X → Y)
(to_fun'_x : to_fun' foo.x = foo.x)
instance [foo X] [foo Y] : has_coe (baz X Y) (bar X) := ⟨baz.to_bar⟩
Oliver Nash (Feb 21 2023 at 16:04):
Now the Lean 4 version:
import Mathlib.Logic.Basic
variable (X Y : Type _)
class Foo := (x : X)
structure Bar [Foo X] :=
(to_fun : X → X)
(to_fun_x : to_fun Foo.x = Foo.x)
structure Baz [Foo X] [Foo Y] extends Bar X :=
(to_fun' : X → Y)
(to_fun'_x : to_fun' Foo.x = Foo.x)
-- Should I drop this or use `CoeOut` instead?
instance [Foo X] [Foo Y] : Coe (Baz X Y) (Bar X) := ⟨Baz.toBar⟩
Oliver Nash (Feb 21 2023 at 16:04):
They both typecheck but the Lean 4 version gets a warning from the linter than the Lean 3 version does not. Specifically:
/- The `dangerousInstance` linter reports:
SOME INSTANCES ARE DANGEROUS
During type-class search, they produce subgoals like `Group ?M`.
Try marking the dangerous arguments as implicit instead. -/
#check instCoeBazBar /- generates subgoals with metavariables: argument 4 inst✝ : Foo ?Y -/
Oliver Nash (Feb 21 2023 at 16:07):
I looked at the places where I would have expected this to come up already in Mathlib4 but all the examples I found (e.g., coercion of linear maps to additive monoid homs) achieve their coercion using @Anne Baanen 's morphisms-as-typeclasses-design (e.g., using semilinear_map_class
and add_monoid_hom_class
) so the issue does not arise.
Oliver Nash (Feb 21 2023 at 16:08):
So what is the right thing to do in a situation like the one I have outlined above. What should be the Lean 4 equivalent of this Lean 3 statement: https://github.com/leanprover-community/mathlib/blob/bd9851ca476957ea4549eb19b40e7b5ade9428cc/src/algebra/lie/basic.lean#L482
Oliver Nash (Feb 21 2023 at 16:09):
Maybe just CoeOut
instead of Coe
?
James Gallicchio (Feb 21 2023 at 16:17):
in the case of your MWE I think you'd expect Foo X
/Foo Y
to always be solved by unification rather than tc inference, so you'd mark them implicit in the instance instead
instance {FX : Foo X} {FY : Foo Y} : Coe (Baz X Y) (Bar X) := sorry
James Gallicchio (Feb 21 2023 at 16:18):
in the mathlib case, you probably can do the same, but there are so many variables floating around in context that it might be a pain to reintroduce them all >_<
Oliver Nash (Feb 21 2023 at 16:21):
The linter still emits a dangerousInstance
warning to me if I make the typeclass variables implicit as you suggest (and it another linter also incorrectly complains that FX
and FY
are unused).
Oliver Nash (Feb 21 2023 at 16:22):
As well as knowing how I should fix this, I'd like to understand what has been changed about coercions and why (provided it's not a rabbit hole).
Oliver Nash (Feb 21 2023 at 16:29):
Aha, in very recently merged code here I see this:
instance coeOutRingHom : CoeOut (A →ₐ[R] B) (A →+* B) :=
⟨AlgHom.toRingHom⟩
#align alg_hom.coe_ring_hom AlgHom.coeOutRingHom
Which suggests that at least one other person thought the right thing to do was just to use CoeOut
instead of Coe
. Maybe @Pol'tta / Kô Miyahara can comment?
Gabriel Ebner (Feb 21 2023 at 17:49):
Yeah, CoeOut is the way to go here.
Oliver Nash (Feb 21 2023 at 17:50):
Thanks!
Pol'tta / Miyahara Kō (Feb 21 2023 at 22:49):
I used CoeOut
in these instances to avoid dangerousInstance
linter.
Yuyang Zhao (Mar 01 2023 at 16:35):
I was confused about the use of CoeOut
in mathlib4 for a long time. Docstr says that use CoeOut α β
if the variables in the type α
are a superset of the variables in β
, but there are fewer AlgHom
s than RingHom
s. Also we used Coe
in MonoidHom.coeToMulHom
MonoidHom.coeToOneHom
etc. I would like to know if there is a reason to use CoeOut
here.
Yuyang Zhao (Mar 01 2023 at 17:30):
Mario Carneiro said:
you would need something like
CoeHead? CoeOut* CoeIn* CoeTail?
whereCoeOut : A -> outParam B
andCoeIn : outParam A -> B
Ah I see. So for homomorphisms (or other FunLike things), it's the opposite of the corresponding type, is it?
Gabriel Ebner (Mar 01 2023 at 18:12):
but there are fewer AlgHoms than RingHoms.
It's not about the cardinality of the set of homomorphisms, it's about number of variables in the Lean type! A →ₐ[R] B
has a variable R
that does not appear in A →* B
, that's what the docstring refers to.
Last updated: Dec 20 2023 at 11:08 UTC