Zulip Chat Archive
Stream: lean4
Topic: Visibility of coercions
Jovan Gerbscheid (Nov 15 2023 at 17:03):
I was doing some tests, and ended up with some code equivalent to this:
def n : Nat := 100
def m : Fin 100 := 50
#eval m ≤ n
I expected the result to be true
, but it is false
. This is because n
is coerced to 0 : Fin 100
. I was not aware of this coercion existing, and I thought it would coerce m
to a Nat
. I don't have an opinion on which coercion is the 'right' one, however I would like to be able to see which coercion is going on. No matter where I put the cursor or hover the mouse, it doesn't say anything about the coercion.
So I would like to see a change to the hover info so that coercions become visible. In Haskell, I remember that hovering over an expression shows you the type of that expression and not just the information about the constant. So in this example, one possible way to resolve my confusion would be by hovering over n
, and the hover info telling me that it has type Fin 100
instead of the Nat
that shows up now.
Eric Wieser (Nov 15 2023 at 17:03):
You can use check
to see the coercion:
def n : Nat := 100
def m : Fin 100 := 50
#check m ≤ n -- m.val ≤ n : Prop
Jovan Gerbscheid (Nov 15 2023 at 17:07):
I see, but what if I'm writing some more complicated function, which happens to have m ≤ n
as a subexpression. e.g.
def f (n : Nat) (m : Fin 100) : Prop := n ≤ m
Mauricio Collares (Nov 15 2023 at 17:07):
And importing Mathlib:
import Mathlib
def n : Nat := 100
def m : Fin 100 := 50
set_option pp.coercions false
#check m ≤ n -- m ≤ Nat.cast n : Prop
Kyle Miller (Nov 15 2023 at 17:22):
@Eric Wieser You're seeing m.val ≤ n
, but we're seeing m ≤ ↑n
.
Eric Wieser (Nov 15 2023 at 17:24):
Yep, my version was without imports
Kyle Miller (Nov 15 2023 at 17:24):
This is really not good that there's a cycle in coercions.
This is fun:
import Mathlib.Tactic
def n : Nat := 100
def m : Fin 100 := 50
#eval m ≤ n -- false
#eval n ≤ m -- false
Eric Wieser (Nov 15 2023 at 17:25):
import Mathlib.Data.Fin.Basic
seem to be enough to switch the behavior
Kyle Miller (Nov 15 2023 at 17:26):
The expression tree elaborator (which ≤
participates in) assumes that the coercion instances form some kind of directed system
Eric Wieser (Nov 15 2023 at 17:27):
Specifically, docs#Fin.instAddMonoidWithOne changes the tide (because it makes #synth NatCast (Fin 100)
succeed)
Eric Wieser (Nov 15 2023 at 18:00):
Arguably Fin.val
is the bad coercion because its not structure-preserving
Kyle Miller (Nov 15 2023 at 18:00):
The coercion from Fin
to Nat
makes sense to have, since it's a subtype coercion, but is there some solution where we can prevent the Nat
to Fin
coercion? I thought having an algebraic structure was what docs#ZMod was for.
Eric Wieser (Nov 15 2023 at 18:01):
ZMod 0
and Fin 0
are very different, so I don't think one can be dropped in as a replacement for the other
Eric Wieser (Nov 15 2023 at 18:02):
Also, Fin (2 ^ n)
is used to implement bitvectors and fixed-width integers, which are available long before Zmod
Kyle Miller (Nov 15 2023 at 18:03):
Is there something we can do about NatCast
not giving Fin
a Nat -> Fin
coercion?
Kyle Miller (Nov 15 2023 at 18:08):
Fin
is used as a plain subtype of Nat
too, for indexing. For that use, having the the coercion to Nat seems to make sense.
I find non-injective coercions to be suspicious in general though. I'd think it would be better if you only got a NatCast
-derived automatic coercion in characteristic 0.
Yaël Dillies (Nov 15 2023 at 18:09):
Isn't the Nat
to Fin
used precisely to have wrapping indices too?
Mario Carneiro (Nov 15 2023 at 18:13):
who wants wrapping indices?
Mario Carneiro (Nov 15 2023 at 18:15):
Kyle Miller said:
Is there something we can do about
NatCast
not givingFin
aNat -> Fin
coercion?
This one isn't NatCast
's fault, it is a "notation typeclass" for exactly this map. Rather, you should blame AddGroupWithOne
for having a NatCast
instance
Eric Wieser (Nov 15 2023 at 18:17):
Mario Carneiro said:
who wants wrapping indices?
Toeplitz matrices are one example
Eric Wieser (Nov 15 2023 at 18:18):
Kyle Miller said:
I find non-injective coercions to be suspicious in general though.
We use them quite a lot for quotient constructions, though we could perhaps allocate a different notation there
Mario Carneiro (Nov 15 2023 at 18:59):
we already do, the \[[ x \]]
notation
Kevin Buzzard (Nov 15 2023 at 19:37):
Or we could remove the additive group structure from Fin
completely and tell users to use ZMod if they want a group structure and fin if they want the finite set. In my brain there's a coercion from Fin n to Nat and a coercion from Nat to ZMod n and no coercions in either of the opposite directions, and this is what distinguishes the set Fin n from the group ZMod n.
Eric Wieser (Nov 15 2023 at 19:38):
Mario Carneiro said:
we already do, the
\[[ x \]]
notation
We don't use that though because it has the wrong type up to semireducibility
Kyle Miller (Nov 15 2023 at 19:47):
I've mentioned before that I'd like having [[x]]
be a notation typeclass. Would this be another point in favor for that?
Mario Carneiro (Nov 15 2023 at 19:57):
yeah I'd love to fix [[x]]
to just do the right thing in quotient wrapper types
Mario Carneiro (Nov 15 2023 at 19:58):
not sure that means making it a notation typeclass, additional magic may be needed
Jovan Gerbscheid (Nov 15 2023 at 21:50):
Maybe we can remove the additive structure of Fin
, and keep the ability to have wrapping indices, by instead having a group action of Int
on Fin n
that shifts the indeces cyclicly?
Eric Wieser (Nov 15 2023 at 22:59):
We probably want that action anyway, regardless of the other conversation here:
import Mathlib
-- this instance might cause some diamonds, or it might be fine
instance AddMonoidWithOne.toAddAction {R} [AddMonoidWithOne R] : AddAction ℕ R :=
AddAction.compHom _ (Nat.castAddMonoidHom R)
-- this instance might cause some diamonds, or it might be fine
instance AddGroupWithOne.toAddAction {R} [AddGroupWithOne R] : AddAction ℤ R :=
AddAction.compHom _ (Int.castAddHom R)
variable (n : ℕ) [NeZero n] in
#synth AddAction ℤ (Fin n)
Yaël Dillies (Nov 16 2023 at 08:02):
Yeah I had a branch adding those fields to AddCommGroupWithOne
in Lean 3.
Eric Wieser (Nov 16 2023 at 10:21):
Did you have a case in mind where they were needed to avoid a diamond?
Eric Wieser (Nov 16 2023 at 10:23):
The only case I can think of where you might want a different defeq is complex numbers, where you could pick either (n + re, im)
or (n + re, 0 + im)
(where my proposal above gives the latter)
Jovan Gerbscheid (Nov 17 2023 at 00:28):
Going back to the original question, I think that it would be very beneficial for lean as a programming language that when you hover your mouse over an expression it shows you the 'true' type of that expression. There is this thing in the infoview called expected type that sort of does this but not quite; For example it doesn't show the coerced type. I want to be able to hover over the coerced m : Fin 100
, and the info telling me that it has type Nat
.
In tactic mode this isn't an issue because you can hover over expressions in the tactic state view (and coercions are shown), so this is just about lean as a (meta) programming language.
Last updated: Dec 20 2023 at 11:08 UTC