Zulip Chat Archive
Stream: mathlib4
Topic: Typeclass automatic synthesising for statements a la op...
Wrenna Robson (Jan 16 2024 at 18:10):
A question that arose while I was working on #9145: so if you have i j : Fin (n + 1)
, with i ≠ j
, then it follows that n ≠ 0
, and so in particular you have an instance of NeZero n
. This is relevant because, essentially, given i j : Fin (n + 1)
, with i ≠ j
, 0 : Fin n
always makes sense. This does come up somewhere: in particular, sometimes in #9145 I have i j : Fin (n + 1)
, with i ≠ j
, and I want to use 0 : Fin n
in the statement, and I couldn't.
What I'm wondering is how to efficiently and elegantly use this fact: I don't think I can use optParam
in the same way that I might if I wanted a proof of n ≠ 0
in the statement, because what I want is a typeclass synthesised from a hypothesis. Is that even possible?
Alternatively, in some ways this reduces to the two following facts:
- Given
i j : Fin (n + 1)
, withi ≠ j
, I can always produce somep: Fin n
. - If I have
p : Fin n
, the notation0 : Fin n
always makes sense (it may or may not be p).
So can I do either of those more elegantly? Do "typeclasses automatically synthesised from hypotheses" even make sense?
Notification Bot (Jan 16 2024 at 18:10):
Wrenna Robson has marked this topic as resolved.
Notification Bot (Jan 16 2024 at 18:10):
Wrenna Robson has marked this topic as unresolved.
Kyle Miller (Jan 16 2024 at 18:24):
Typeclass synthesis doesn't look at hypotheses, but something you do is make a function neZeroOfFinNe : {i j : Fin (n + 1)} -> i ≠ j -> NeZero n
and then given h : i ≠ j
write have := neZeroOfFinNe h
either in your proof or as a line of a definition.
Wrenna Robson (Jan 16 2024 at 19:43):
Hmm, how do you fit it into a definition? Like that can be part of a statement?
Kyle Miller (Jan 16 2024 at 19:47):
You can use haveI := neZeroOfFinNe h; ...
in a statement and have it be eliminated from the type. You can't use it for variables before the colon though.
Wrenna Robson (Jan 16 2024 at 21:01):
Thanks, that is perfect.
Wrenna Robson (Jan 16 2024 at 21:01):
Any suggestions where such a neZeroOfFinNe
would go? Data/Fin/Basic?
Emilie (Shad Amethyst) (Jan 16 2024 at 22:14):
I would also have something of the likes of instance neZero_of_nonTrivial_fin_succ (nt : Nontrivial (Fin n.succ)) : NeZero n
Emilie (Shad Amethyst) (Jan 16 2024 at 22:21):
You also have that NeZero n ↔ NonEmpty (Fin n) ↔ Nontrivial (Fin n.succ)
, though I don't know if the typeclass solver can handle loops. The left equivalence is covered by docs#Fin.pos_iff_nonempty already and the right equivalence can be derived from docs#Fin.nontrivial_iff_two_le
Wrenna Robson (Jan 17 2024 at 01:15):
If we had instance neZero_of_nonTrivial_fin_succ [Nontrivial (Fin n.succ)] : NeZero n
, would that then let the solver do the inference (taking it as a typeclass)?
I suspect what you want is instance [Nontrivial (Fin n.succ)] : NonEmpty (Fin n)
and instance [NonEmpty (Fin n)] : NeZero n
, and that way avoid the loop in the typeclass solver.
Eric Wieser (Jan 17 2024 at 02:15):
That second instance already exists in reverse
Wrenna Robson (Jan 17 2024 at 02:16):
Oops. I knew we had docs#Fin.pos_iff_nonempty but didn't realise we had the instance.
Wrenna Robson (Jan 17 2024 at 02:16):
That feels like... the less useful order in some ways? Idk.
Eric Wieser (Jan 17 2024 at 02:18):
Well, it follows from the fact that when n is not zero, there is a Zero
Wrenna Robson (Jan 17 2024 at 02:19):
Indeed.
Wrenna Robson (Jan 17 2024 at 02:23):
It's just one of those slightly troublesome things where frankly it's basically trivial except somehow it isn't.
Wrenna Robson (Jan 17 2024 at 02:26):
Annoyingly it's slightly asymmetrical as well, in the sense that you don't have a similar issue for last
(precisely because last n
is in Fin (n +1), I.e. there's no analogy of "NeZero means you have a last".
Eric Wieser (Jan 17 2024 at 02:29):
I think generalizing last in that way spoiled be reasonable?
Eric Wieser (Jan 17 2024 at 02:30):
Oh, I guess it maybe ends up with a bad defeq
Wrenna Robson (Jan 17 2024 at 02:31):
Yeah the issue is, what would you define last 0
as? In a sense the better notation is arguably \top
Wrenna Robson (Jan 17 2024 at 02:31):
Though obviously in general using \bot instead of 0 would be... eccentric.
Wrenna Robson (Jan 17 2024 at 02:38):
Of course you could define last : Fin n
as rev 0
.
Eric Wieser (Jan 17 2024 at 03:01):
Wrenna Robson said:
Yeah the issue is, what would you define
last 0
as?
False.elim _
Wrenna Robson (Jan 17 2024 at 08:02):
Hmm I'm not sure that works.
Emilie (Shad Amethyst) (Jan 17 2024 at 10:14):
It's the equivalent of unreachable!()
in rust
Wrenna Robson (Jan 17 2024 at 10:15):
right...
Mario Carneiro (Jan 17 2024 at 10:15):
the equivalent of unreachable!()
in rust is unreachable!
, the equivalent of False.elim
in rust is match x {}
Wrenna Robson (Jan 17 2024 at 10:15):
I just don't quite follow what you're eliminating.
Mario Carneiro (Jan 17 2024 at 10:16):
Fin0.elim
is like False.elim
but it takes an element of Fin 0
instead
Wrenna Robson (Jan 17 2024 at 10:16):
Right.
Mario Carneiro (Jan 17 2024 at 10:16):
you can also just pattern match on it, the compiler knows it is empty
Wrenna Robson (Jan 17 2024 at 10:17):
But I asked what you'd define last 0
as if you made last n
a member of Fin n
.
Mario Carneiro (Jan 17 2024 at 10:18):
oh, I was thinking this was a function that takes a Fin n
, of course if it's just producing a Fin n
from nothing then you are in trouble for n = 0
Wrenna Robson (Jan 17 2024 at 10:19):
Indeed. But you can make it work if you add a [NeZero n]
typeclass.
Wrenna Robson (Jan 17 2024 at 10:19):
I was just remarking that that isn't currently an option.
Emilie (Shad Amethyst) (Jan 17 2024 at 10:21):
An instance of instance [NeZero n] : OrderTop (Fin n)
would be nice to have, I think.
Also, speaking of option
, you could wrap the result in an Option
Wrenna Robson (Jan 17 2024 at 10:23):
Yeah I don't know if the OrderTop instance currently works for that, I think we just have the one for n +1
. It can be a bit of a pain writing lemmas (in the zero case) because I never know if I should have two versions or just the [NeZero]
one.
Yaël Dillies (Jan 17 2024 at 10:28):
We agreed a long time ago that instances about Fin (n + 1)
should instead be instances about Fin n
where NeZero n
. Feel free to fix whatever instances are not following that rule.
Wrenna Robson (Jan 17 2024 at 10:28):
Oh really?
Wrenna Robson (Jan 17 2024 at 10:29):
Then I think the best strategy would be to change last n
so that instead it's just called last
, make it a member of Fin n, and define it as Fin.rev 0 as a bonus.
Yaël Dillies (Jan 17 2024 at 10:30):
Why not just use ⊤
then?
Wrenna Robson (Jan 17 2024 at 10:30):
I was just typing that!
Wrenna Robson (Jan 17 2024 at 10:31):
Well, I don't know why we decided to have last
in the first place.
Yaël Dillies (Jan 17 2024 at 10:31):
I think it's because it's easier to type (last n)
than (⊤ : Fin (n + 1))
when the expected type is unavailable.
Wrenna Robson (Jan 17 2024 at 10:32):
As I was saying yesterday, arguably one could also use \bot instead of 0 in a lot of places but that is a little eccentric.
Yaël Dillies (Jan 17 2024 at 10:32):
Yeah but that's a different situation: 0
has an algebraic meaning that last n
doesn't have.
Wrenna Robson (Jan 17 2024 at 10:32):
Yaël Dillies said:
I think it's because it's easier to type
(last n)
than(⊤ : Fin (n + 1))
when the expected type is unavailable.
I suppose you could define last n
as the same, make the n
explicit.
Wrenna Robson (Jan 17 2024 at 10:33):
Yaël Dillies said:
Yeah but that's a different situation:
0
has an algebraic meaning thatlast n
doesn't have.
Yes I agree - but we tend to use 0 even in the order-theoretic places for Fin.
Wrenna Robson (Jan 17 2024 at 10:33):
Which I'm not necessarily disagreeing with, to be clear.
Wrenna Robson (Jan 17 2024 at 10:34):
But e.g. Fin.cases
and Fin.lastCases
are somewhat more about ordering than they are about algebraic properties.
Yaël Dillies (Jan 17 2024 at 10:34):
I'm just arguing that 0
and last n
can't be thought about symmetrically because they have differing algebraic relevance (even though they have identical order theoretic relevance).
Wrenna Robson (Jan 17 2024 at 10:35):
Ah I see what you mean
Wrenna Robson (Jan 17 2024 at 10:36):
Yes, indeed. I suppose you could talk about the algebraic properties of last n
(for one thing, it's the additive inverse of 1...) but I can't ever see why that would be easier.
Yaël Dillies (Jan 17 2024 at 10:36):
Well that wouldn't be last n
, right? That would be -1
. Spelling matters.
Wrenna Robson (Jan 17 2024 at 10:37):
True, true.
Wrenna Robson (Jan 17 2024 at 10:37):
As you say, 0 is a bit special.
Mario Carneiro (Jan 17 2024 at 10:38):
-1
is a bit pathological though, because it does something weird on Fin 1
Wrenna Robson (Jan 17 2024 at 10:38):
Does it?
Wrenna Robson (Jan 17 2024 at 10:38):
I mean it's also 0, obviously.
Yaël Dillies (Jan 17 2024 at 10:38):
How so? It's still the additive inverse of 1
.
Mario Carneiro (Jan 17 2024 at 10:38):
well 1 : Fin n
is 1
for every n
except for n = 1
, where it is 0
instead
Wrenna Robson (Jan 17 2024 at 10:39):
yes I'm not quite sure why it's not also 1.
Yaël Dillies (Jan 17 2024 at 10:39):
You mean (1 : Fin n).val
.
Wrenna Robson (Jan 17 2024 at 10:39):
Oh I see what you mean.
Mario Carneiro (Jan 17 2024 at 10:39):
It works out up to (propositional) equality, but it's less uniform compared to last
which is n - 1
for every n > 0
Wrenna Robson (Jan 17 2024 at 10:40):
Yes that can occasionally trip one up. Clearly the solution is to start things at Fin 2
. Fin 1
and Fin 0
are silly types: let's never go there ;)
Wrenna Robson (Jan 17 2024 at 10:41):
Mario Carneiro said:
It works out up to (propositional) equality, but it's less uniform compared to
last
which isn - 1
for everyn > 0
Yes in this sense last
is closer to 0 (which makes sense!) in that it's only pathological at 0 (where nothing exists anyway).
Mario Carneiro (Jan 17 2024 at 10:41):
too bad we don't have a ~
operator
Mario Carneiro (Jan 17 2024 at 10:42):
does ~~~0
work?
Wrenna Robson (Jan 17 2024 at 10:42):
as I say this is why I think I like rev 0
as its definition.
Wrenna Robson (Jan 17 2024 at 10:42):
What would ~
do?
Mario Carneiro (Jan 17 2024 at 10:42):
rev
Wrenna Robson (Jan 17 2024 at 10:42):
Right. Yeah, would be nice.
Mario Carneiro (Jan 17 2024 at 10:42):
I mean it as in the C bitwise negation operator
Mario Carneiro (Jan 17 2024 at 10:42):
which is -n-1
Wrenna Robson (Jan 17 2024 at 10:57):
Right right. Do we use that notation for anything?
Mario Carneiro (Jan 17 2024 at 10:58):
bitwise ops
Wrenna Robson (Jan 17 2024 at 10:58):
Which... I think this would be consistent with (on Fin (2^m)?)
Wrenna Robson (Jan 17 2024 at 12:43):
@Yaël Dillies yeah it looks like the bounded order instance on Fin is for Fin (n + 1) instead of NeZero n. That wants changing, right?
Wrenna Robson (Jan 17 2024 at 12:43):
Unfortunately the definition of last is in std so it can't really change. We could have a last' that works more as we might want...
Yaël Dillies (Jan 17 2024 at 12:44):
NeZero
might make it to Std eventually
Wrenna Robson (Jan 17 2024 at 12:45):
That would be nice
Last updated: May 02 2025 at 03:31 UTC