Zulip Chat Archive
Stream: Is there code for X?
Topic: Preorder on Option
Wrenna Robson (Dec 19 2023 at 17:32):
Does Option have any kind of preorder relationship defined (assuming the underlying type does)? I've run myself into a mild pickle through assuming it did but I'm not sure it does.
Mario Carneiro (Dec 19 2023 at 17:36):
See docs#WithTop and docs#WithBot
Mario Carneiro (Dec 19 2023 at 17:37):
depending on whether you want none
to be at the top or bottom
Eric Wieser (Dec 19 2023 at 18:11):
I guess you could put an order on Option X
that has none
as incomparable?
Wrenna Robson (Dec 19 2023 at 18:27):
Yeah, that's what I was assuming.
Wrenna Robson (Dec 19 2023 at 18:27):
Or hoping for.
Wrenna Robson (Dec 19 2023 at 18:27):
Oddly there is an LT instance defined? But it isn't much use.
Wrenna Robson (Dec 19 2023 at 18:50):
But what I want is
instance (priority := 10) le [LE α] : LE (Option α) := ⟨Option.Rel (. ≤ .)⟩
instance (priority := 10) lt [LT α] : LT (Option α) := ⟨Option.Rel (. < .)⟩
(and then ideally a preorder...)
Wrenna Robson (Dec 19 2023 at 19:07):
Wait no. I want that for LE, for LT I don't because obviously Bot should not be LT itself as then you can't make a Preorder
Wrenna Robson (Dec 19 2023 at 19:08):
Urrrgh. That might be a day's work buggered if this is a challenge. I assumed (given that < worked!) that it would just nicely inherit the structure.
Yaël Dillies (Dec 19 2023 at 19:09):
Just define a < b ↔ a ≤ b ∧ ¬ b ≤ a
Wrenna Robson (Dec 19 2023 at 19:09):
Sure, that's what I want.
Wrenna Robson (Dec 19 2023 at 19:10):
But obviously if it doesn't already exist there will be lots of fiddly lemmas to sort.
Wrenna Robson (Dec 20 2023 at 12:26):
Also, instLTOption
exists by default, and makes none lt everything else - which I don't particularly want. But also trying to move to WithBot or WithTop means parts of the Option API don't work - I want to retain that.
Wrenna Robson (Dec 20 2023 at 12:26):
That instance is in Init.Data.Option.Basic
Eric Wieser (Dec 20 2023 at 12:26):
Yaël Dillies (Dec 20 2023 at 12:26):
Oh that's ancient
Wrenna Robson (Dec 20 2023 at 12:27):
Indeed, but because it already exists it somewhat gets in the way for me/was a footgun because <
worked, but actually it didn't really have any way of using it properly.
Eric Wieser (Dec 20 2023 at 12:27):
<
is defined correctly, isn't it?
Eric Wieser (Dec 20 2023 at 12:28):
Oh wait, no it isn't
Eric Wieser (Dec 20 2023 at 12:28):
It declares none
as a bottom element
Wrenna Robson (Dec 20 2023 at 12:28):
It uses Option.lt
, so, no.
Eric Wieser (Dec 20 2023 at 12:28):
I think we should remove it, if you want that behavior you should use WithBot
Wrenna Robson (Dec 20 2023 at 12:28):
Yes, I agree.
Eric Wieser (Dec 20 2023 at 12:29):
Eric Wieser said:
I guess you could put an order on
Option X
that hasnone
as incomparable?
I think this is a good idea though
Wrenna Robson (Dec 20 2023 at 12:29):
Yep.
Wrenna Robson (Dec 20 2023 at 12:30):
I think what you do is
- define <= as Option.Rel (le)
- Define < as Yaël says above, the standard a < b if a <=b and not (b <= a) thing.
Wrenna Robson (Dec 20 2023 at 12:30):
I believe that will also give a Preorder if your base type has one. I assume you also get PartialOrder and LinearOrder as appropriate too?
Yaël Dillies (Dec 20 2023 at 12:31):
Actually if you want to make none
incomparable you can just define ¬ none < none
, ¬ none < some b
, ¬ some a < none
and some a < some b ↔ a < b
and that will give you nice definitional properties
Wrenna Robson (Dec 20 2023 at 12:32):
Well, yeah - that also looks great. Just would like the inheriting thing really!
Wrenna Robson (Dec 20 2023 at 12:33):
I don't have time today (or honestly the mental space - I'm not in a good place with the stres right now) to put a PR together, but it seems like honestly it would be good. And this feels like the "right" order to have on Option as opposed to WithBot or WithTop.
Wrenna Robson (Dec 20 2023 at 12:33):
(We don't have a notation for none
and some x
, right? You just write that?)
Yaël Dillies (Dec 20 2023 at 12:34):
some
is also the coercion
Eric Wieser (Dec 20 2023 at 12:34):
Wrenna Robson said:
I believe that will also give a Preorder if your base type has one. I assume you also get PartialOrder and LinearOrder as appropriate too?
Not a linear order, because none
is incomparable and therefore le_total
isn't true
Wrenna Robson (Dec 20 2023 at 12:41):
Oh yes ofc
Wrenna Robson (Dec 20 2023 at 12:42):
Eric Wieser said:
Wrenna Robson said:
I believe that will also give a Preorder if your base type has one. I assume you also get PartialOrder and LinearOrder as appropriate too?
Not a linear order, because
none
is incomparable and thereforele_total
isn't true
Oh yes. But I think it would be a perfectly good PartialOrder?
Eric Wieser (Dec 20 2023 at 12:45):
Wrenna Robson said:
I don't have time today (or honestly the mental space - I'm not in a good place with the stres right now) to put a PR together
A middle ground that maybe we should encourage more is to create a github issue to track the idea
Eric Wieser (Dec 20 2023 at 12:45):
Heck, this might even be a "good first issue"
Wrenna Robson (Dec 20 2023 at 12:49):
example {α : Type*} [Preorder α] : Preorder (Option α) where
lt a b := match a, b with | some a, some b => a < b | _, _ => False
le a b := match a, b with | none, none => True | some a, some b => a ≤ b | _, _ => False
le_refl a := match a with | none => sorry | some a => sorry
le_trans a b c := sorry
Not actually sure how you fill the sorries here. Also I get some kind of weird error:
type mismatch
HEq.rfl
has type
HEq ?m.92552 ?m.92552 : Prop
but is expected to have type
a✝ < b✝ ↔ a✝ ≤ b✝ ∧ ¬b✝ ≤ a✝ : Prop
But I assume this is something to do with the existing LT instance interfering? IDK.
Wrenna Robson (Dec 20 2023 at 12:54):
It seems like there are two, maybe three PRs here:
- kill the existing Option instance (That is in
Init.Data.Option.Basic
- is that Mathlib? Deeper?) - Add in a new instance for Option (where should this go?)
- Add the Preorder and Partial Order results.
Wrenna Robson (Dec 20 2023 at 13:14):
Wow yeah it looks like that instance is in the actual Lean 4 repo. I don't even know if they accept PRs.
Wrenna Robson (Dec 20 2023 at 13:17):
Is there a way to supress an existing instance? I wonder if that instance is actually used by anything.
Eric Wieser (Dec 20 2023 at 13:29):
The weird error is coming from the lt_iff_le_not_le
field that you omitted
Wrenna Robson (Dec 20 2023 at 13:30):
aha
Wrenna Robson (Dec 20 2023 at 13:30):
It didn't list that as a missing field so I didn't think to.
Eric Wieser (Dec 20 2023 at 13:39):
Here's a full proof:
example {α : Type*} [Preorder α] : Preorder (Option α) where
lt
| some a, some b => a < b
| _, _ => False
le
| none, none => True
| some a, some b => a ≤ b | _, _ => False
le_refl
| none => trivial
| some a => le_refl a
le_trans
| none, none, none, _, _ => trivial
| some a, some b, some c, hab, hbc => le_trans hab hbc
lt_iff_le_not_le a b :=
⟨(match a, b, · with | some a, some b, h => lt_iff_le_not_le.1 h),
(match a, b, · with
| none, none, ⟨_, hn⟩ => hn trivial
| some a, some b, h => lt_iff_le_not_le.2 h)⟩
Wrenna Robson (Dec 20 2023 at 13:40):
Aha. Thanks, I was trying to use rfl
where you have trivial
but I see now the issue.
Eric Wieser (Dec 20 2023 at 13:40):
The last one is a fun golfing challenge
Yaël Dillies (Dec 20 2023 at 13:40):
Is there not some existing inductive proposition to lift α → β → Prop
to Option α → Option β → Prop
?
Eric Wieser (Dec 20 2023 at 13:40):
Yes, but that only works for le
Wrenna Robson (Dec 20 2023 at 13:40):
Yes, Option.Rel
.
Yaël Dillies (Dec 20 2023 at 13:40):
Surely you don't need iff_iff_implies_and_implies
?
Wrenna Robson (Dec 20 2023 at 13:41):
Yes you can't lift <
using that.
Yaël Dillies (Dec 20 2023 at 13:41):
Wrenna Robson said:
Yes,
Option.Rel
.
Yeah but without the none
case
Wrenna Robson (Dec 20 2023 at 13:41):
Oh I see. I haven't found one!
Eric Wieser (Dec 20 2023 at 13:42):
I guess we could adjust docs#Option.Rel to take the none
value too
Eric Wieser (Dec 20 2023 at 13:42):
Or define Option.StrictRel
Wrenna Robson (Dec 20 2023 at 13:43):
Option.lt
imposes the "none is least" condition and is a bit of a trap imo.
Wrenna Robson (Dec 20 2023 at 13:44):
You would possibly want to consider nixing it at the same time as nixing instLTOption
, and add Option.StrictRel
as you say.
Eric Wieser (Dec 20 2023 at 13:46):
Wrenna Robson said:
Wow yeah it looks like that instance is in the actual Lean 4 repo. I don't even know if they accept PRs.
You could make a draft PR that deletes the instance and sees what breaks (or just do this in a fork)
Wrenna Robson (Dec 20 2023 at 15:32):
Having experimented with deleting it, the answer seems to be: not much. If it builds OK I might well actually submit a PR if that's in line with the lean4
contribution guidance.
Wrenna Robson (Dec 20 2023 at 15:33):
Looks like I should open an issue first.
Eric Wieser (Dec 20 2023 at 15:43):
My process has been 1) open a draft PR, check it compiles, discuss on zulip 2) write the issue, linking the zulip thread 3) promote the draft PR to a real PR
Eric Wieser (Dec 20 2023 at 15:43):
The draft PR is nice because it also tests Std and mathlib for you
Wrenna Robson (Dec 20 2023 at 15:48):
https://github.com/leanprover/lean4/issues/3100
Wrenna Robson (Dec 20 2023 at 15:49):
Their contribution guidelines say "make an issue before making a PR". I am not sure how to distinguish between a draft PR and a real PR.
Eric Wieser (Dec 20 2023 at 15:49):
When you make a PR the "open PR" button has a "draft" dropdown
Wrenna Robson (Dec 20 2023 at 15:50):
Oh interesting. Perhaps if it compiles fine locally I will do that.
Wrenna Robson (Dec 20 2023 at 15:51):
Interestingly it couldn't even successfully detect the Lean version in the file when I opened it, I assume because it's just running at the bottom of the stack and a project isn't set up? Idk.
Wrenna Robson (Dec 20 2023 at 20:48):
How do I link to commits in repos other than mathlib?
Yaël Dillies (Dec 20 2023 at 20:49):
Wrenna Robson (Dec 20 2023 at 20:51):
Ta
Wrenna Robson (Dec 20 2023 at 23:08):
leanprover/lean4#3102 and leanprover/std4#473 may be of interest then
Eric Wieser (Dec 20 2023 at 23:19):
neat, everything is green with the core change
Wrenna Robson (Dec 20 2023 at 23:46):
Yep, it seems to genuinely break nothing. So I am hoping it will be an easy decision for them.
Wrenna Robson (Dec 20 2023 at 23:46):
What is the theorem for like - so I have Option.Rel. I know Option.Rel r (some a) (some b)
. So I can conclude that r a b.
Eric Wieser (Dec 21 2023 at 00:45):
That's Option.Rel.rec
Eric Wieser (Dec 21 2023 at 00:45):
Or just cases h
Wrenna Robson (Dec 21 2023 at 08:40):
Aye, cases h worked fine, just was trying to do it as a term. I was using Option.Rel.casesOn and it wasn't really working.
Wrenna Robson (Dec 21 2023 at 08:41):
Incidentally, there is an argument that there shouldn't be any kind of ordering on Option at all, and we have a third synonym for the incomparable ordering. What do you think?
Wrenna Robson (Dec 21 2023 at 08:41):
Personally I like the idea of Option having an ordering and it being that one, because to me it's the best "default".
Wrenna Robson (Dec 21 2023 at 09:44):
inductive StrictRel (r : α → β → Prop) : Option α → Option β → Prop
/-- If `a ~ b`, then `some a ~ some b` -/
| some {a b} : r a b → StrictRel r (some a) (some b)
instance instLTOption' [LT α] : LT (Option (α)) := ⟨StrictRel (· < ·)⟩
instance instLEOption [LE α] : LE (Option (α)) := ⟨Rel (· ≤ ·)⟩
@[simp]
lemma none_le_none {α : Type*} [LE α] : (none : Option α) ≤ none := Rel.none
@[simp]
lemma not_none_le_some {α : Type*} [LE α] {a : α} : ¬ none ≤ some a := fun ha => by cases ha
@[simp]
lemma not_some_le_none {α : Type*} [LE α] {a : α} : ¬ some a ≤ none := fun ha => by cases ha
lemma some_le_some_of_le {α : Type*} [LE α] {a b : α} (hab : a ≤ b) :
some a ≤ some b := Rel.some hab
lemma le_of_some_le_some {α : Type*} [LE α] {a b : α} (hab : some a ≤ some b) :
a ≤ b := by cases hab; assumption
@[simp]
lemma some_le_some_iff {α : Type*} [LE α] {a b : α} : some a ≤ some b ↔ a ≤ b :=
⟨le_of_some_le_some, some_le_some_of_le⟩
@[simp]
lemma not_none_lt_none {α : Type*} [LT α] : ¬ (none : Option α) < none := fun ha => by cases ha
@[simp]
lemma not_none_lt_some {α : Type*} [LT α] {a : α} :
¬ (none : Option α) < some a := fun ha => by cases ha
@[simp]
lemma not_some_lt_none {α : Type*} [LT α] {a : α} :
¬ some a < (none : Option α) := fun ha => by cases ha
lemma some_lt_some_of_lt {α : Type*} [LT α] {a b : α} (hab : a < b) :
some a < some b := StrictRel.some hab
lemma lt_of_some_lt_some {α : Type*} [LT α] {a b : α} (hab : some a < some b) :
a < b := by cases hab; assumption
@[simp]
lemma some_lt_some_iff {α : Type*} [LT α] {a b : α} : some a < some b ↔ a < b :=
⟨lt_of_some_lt_some, some_lt_some_of_lt⟩
instance {α : Type*} [Preorder α] : Preorder (Option α) where
le_refl a := a.casesOn Rel.none (fun _ => Rel.some (le_refl _))
le_trans a b c hab hbc := by
cases' hab with _ _ hab
· cases' hbc with _ _ hbc
exact Rel.some (hab.trans hbc)
· cases hbc
exact Rel.none
lt_iff_le_not_le a b := Iff.intro (fun hab => by
cases' hab with _ _ hab
simp_rw [some_le_some_iff]
exact le_not_le_of_lt hab)
(fun ⟨hab, hba⟩ => by
cases' hab with _ _ hab
· simp_rw [some_le_some_iff] at hba
exact some_lt_some_of_lt (lt_iff_le_not_le.mpr ⟨hab, hba⟩)
· exact (hba none_le_none).elim)
instance {α : Type*} [PartialOrder α] : PartialOrder (Option α) where
le_antisymm a b hab hba := by
cases' hab with _ _ hab
· exact (some.injEq _ _).symm ▸ (le_antisymm hab (le_of_some_le_some hba))
· exact rfl
Wrenna Robson (Dec 21 2023 at 09:55):
Now, where in Mathlib should this go? We don't seem to import any order files in the basic Option/Data/* files. @Yaël Dillies, should it go in Order/Basic.lean?
Yaël Dillies (Dec 21 2023 at 09:56):
Either there or in a new Data.Option.Order
file
Wrenna Robson (Dec 21 2023 at 09:58):
That has something to commend it.
Wrenna Robson (Dec 21 2023 at 09:58):
There are various other things - some
is an order embedding, I guess some results about Option.get
, that sort of thing - that really are very Option-flavoured and might need other order imports.
Wrenna Robson (Dec 21 2023 at 09:59):
Data/Option/Order.lean would seem reasonable
Wrenna Robson (Dec 21 2023 at 10:05):
Incidentally we should probably remove Option.rel
from Mathlib.
Wrenna Robson (Dec 21 2023 at 10:06):
Give it is identical to Option.Rel
in Standard
Kim Morrison (Dec 21 2023 at 10:42):
I'm skeptical about this being the "default". It would not have occurred to me as being better than the WithBot
interpretation, which for me is the obviously correct one. :-)
Kim Morrison (Dec 21 2023 at 10:43):
(Just like false < true
for everyone, right!? :-)
Wrenna Robson (Dec 21 2023 at 11:09):
Yeah, I think that's a valid way to feel. I also think it's legitimate to simply not have an ordering on Option itself. Do you have a good name for, uh, the incomparable space, I don't know what to call it?
Kim Morrison (Dec 21 2023 at 11:11):
IncomparableNoneOption
? :-)
Wrenna Robson (Dec 21 2023 at 11:12):
That feels a little long to me.
Yaël Dillies (Dec 21 2023 at 11:13):
I think the incomparable order is a decent default.
Wrenna Robson (Dec 21 2023 at 11:13):
Fundamentally I was in a context where None just had no meaning, a partial function sort of thing, and in that context I don't want theorems to be accidentally true without caveating for good inputs. To me, that's the appropriate place to use the incomparable one - and it's the closest to the semantic meaning of Option in my head.
Wrenna Robson (Dec 21 2023 at 11:14):
Option = "I've added an element, and literally it represents nothing except that it exists and is distinct to all things that correspond to a value, and I want to have a partial order on this if I can and to do that I guess it needs to have minimal relations"
Wrenna Robson (Dec 21 2023 at 11:14):
"WithBot = all of that but it's less than everything"
Wrenna Robson (Dec 21 2023 at 11:15):
So that's I think why it's the default for me - it's a kind of "minimal property", the closure in a sense.
Kim Morrison (Dec 21 2023 at 11:16):
I asked ChatGPT for whimsical options for a name for an incomparable type synonym. Most were not that great, but I did like WildCard α
.
Wrenna Robson (Dec 21 2023 at 11:16):
That's fun.
Wrenna Robson (Dec 21 2023 at 11:17):
It also somewhat represents having a default or error value, so WithDefault
is not bad.
Wrenna Robson (Dec 21 2023 at 11:18):
Better yet it fits the naming convention.
Wrenna Robson (Dec 21 2023 at 11:19):
It would be ideal if the API for this was as straightforward to use as possible. Once you create a synonym that does create a debt of lots of fiddly little bits you want to do.
Wrenna Robson (Dec 21 2023 at 11:19):
I also suspect there's a bunch of places we currently use Option where semantically WithDefault
is more appropriate.
Yaël Dillies (Dec 21 2023 at 11:20):
I really don't think there's any point bothering with a type synonym here.
Wrenna Robson (Dec 21 2023 at 11:21):
I mean that would be my wish! But clearly there's differing views.
Mario Carneiro (Dec 21 2023 at 11:21):
I'm concerned about the programming use case though, I don't think we want to make people use a type synonym to be able to put options in map keys
Wrenna Robson (Dec 21 2023 at 11:22):
What's the requirement for that?
Wrenna Robson (Dec 21 2023 at 11:22):
It needs to be ordered?
Mario Carneiro (Dec 21 2023 at 11:22):
Option T
should have a total order if T
does
Wrenna Robson (Dec 21 2023 at 11:22):
Right. I mean that wasn't the case already so we're going to need to add something. (Indeed the problem was that Option T actually didn't have anything really.)
Wrenna Robson (Dec 21 2023 at 11:24):
If Option T
has to have a total order if T does, I don't really see how you can avoid having it be one of WithBot or WithTop. In which case, why have them?
Wrenna Robson (Dec 21 2023 at 11:26):
Personally I think it should be the case that it has a partial order (or at the very least a preorder) if T does. It's entirely clear that for the most part of it that is just T wearing a hat you know what the order should be. There's just this other element you need to stick on.
Eric Wieser (Dec 21 2023 at 11:29):
Mario Carneiro said:
I'm concerned about the programming use case though, I don't think we want to make people use a type synonym to be able to put options in map keys
Would a solution be to have maps use [Trunc (LinearOrder X)]
as a typeclass instead of LinearOrder X
?
Wrenna Robson (Dec 21 2023 at 11:29):
@Mario Carneiro arrrrguably if I want to create a map with Option as its keys, that should be better thought of as an Option (map). Like in the sense that I'm uncomfortable with the idea that you could create a map such that putting None in gave data out.
Eric Wieser (Dec 21 2023 at 11:30):
There are cases where there is obviously an order, but while the exact choice of order isn't clear, it's not actually relevant to the implementation
Mario Carneiro (Dec 21 2023 at 11:30):
Eric Wieser said:
Mario Carneiro said:
I'm concerned about the programming use case though, I don't think we want to make people use a type synonym to be able to put options in map keys
Would a solution be to have maps use
[Trunc (LinearOrder X)]
as a typeclass instead ofLinearOrder X
?
No.
Wrenna Robson (Dec 21 2023 at 11:30):
Like kinda what Option wants is to be able to use it as monadically as possible, where essentially I chunter along using it but if at any point a None appears everything after it is None too.
Eric Wieser (Dec 21 2023 at 11:31):
(this also feels a bit like the Repr (Multiset X)
problem, where on X = Prod A B
we want to print in a lexicographic order, even though it's not as canonical as the standard order)
Mario Carneiro (Dec 21 2023 at 11:31):
Wrenna Robson said:
Mario Carneiro arrrrguably if I want to create a map with Option as its keys, that should be better thought of as an Option (map). Like in the sense that I'm uncomfortable with the idea that you could create a map such that putting None in gave data out.
That's not what a map with option keys is though, a HashMap (Option K) V
is isomorphic to Option V x HashMap K V
Eric Wieser (Dec 21 2023 at 11:31):
What's the story for HashMap (Prod X Y) Z
right now? Do you have to use HashMap (Lex (Prod X Y)) Z
?
Mario Carneiro (Dec 21 2023 at 11:32):
Quotients make printing and lots of other things difficult. Consider the Repr Real
instance which cannot be made safe
Mario Carneiro (Dec 21 2023 at 11:32):
No hashmaps of products work fine
Wrenna Robson (Dec 21 2023 at 11:32):
Mario Carneiro said:
Wrenna Robson said:
Mario Carneiro arrrrguably if I want to create a map with Option as its keys, that should be better thought of as an Option (map). Like in the sense that I'm uncomfortable with the idea that you could create a map such that putting None in gave data out.
That's not what a map with option keys is though, a
HashMap (Option K) V
is isomorphic toOption V x HashMap K V
Hang on, why isn't it V x HashMap K V
?
Eric Wieser (Dec 21 2023 at 11:33):
Because the none
key could be absent
Wrenna Robson (Dec 21 2023 at 11:33):
For that matter why is it prod and not sum - ah!
Wrenna Robson (Dec 21 2023 at 11:33):
Right yes of course
Eric Wieser (Dec 21 2023 at 11:34):
Mario Carneiro said:
I'm concerned about the programming use case though, I don't think we want to make people use a type synonym to be able to put options in map keys
I think I'm missing something; where is the order requirement coming from for map keys? docs#Std.HashMap doesn't have one
Wrenna Robson (Dec 21 2023 at 11:34):
Was trying to work out where that extra state came from. Still think it seems more like a sum though.
Mario Carneiro (Dec 21 2023 at 11:34):
For hashmaps actually everything is fine, these types already have derived hash and eq impls
Mario Carneiro (Dec 21 2023 at 11:35):
it's order-based maps that require ord impls
Mario Carneiro (Dec 21 2023 at 11:35):
like RBMap
Eric Wieser (Dec 21 2023 at 11:35):
Maybe we should have a HasLexicographicOrder X Y
typeclass which provides a map from a type X
to an outparam linearly-ordered type Y
?
Eric Wieser (Dec 21 2023 at 11:36):
Though maybe LinearOrder (Lex X)
is sufficient for that and we should just put the with_bot order on Lex Option
Mario Carneiro (Dec 21 2023 at 11:36):
that would also be bad in the programming use case, it adds an additional computationally relevant operation on the hot path
Eric Wieser (Dec 21 2023 at 11:36):
Is an identity function computationally relevant?
Mario Carneiro (Dec 21 2023 at 11:36):
only if it's the identity function
Eric Wieser (Dec 21 2023 at 11:36):
Or is the point that the compiler can't see its an identity function?
Mario Carneiro (Dec 21 2023 at 11:37):
it may not be the identity
Mario Carneiro (Dec 21 2023 at 11:37):
and in the derived impls it won't be
Mario Carneiro (Dec 21 2023 at 11:38):
even if it is Prod.map id id
I don't think the compiler will know it is the identity, but I expect some of these to also be genuinely non-identity maps
Wrenna Robson (Dec 21 2023 at 11:39):
And all these problems are solved if none < some k
?
Mario Carneiro (Dec 21 2023 at 11:39):
yes, at least for option
Eric Wieser (Dec 21 2023 at 11:39):
In the cases where it's a non-identity map, aren't we just choosing between baking that map into the comparator vs storing it separately?
Mario Carneiro (Dec 21 2023 at 11:39):
I think a better approach would be HasWeirdOrd X
which has derived total ordering impls
Eric Wieser (Dec 21 2023 at 11:39):
The latter is arguably more efficient because you can avoid recomputing the embedding in the linear order when doing multiple comparisons
Wrenna Robson (Dec 21 2023 at 11:40):
Mario Carneiro said:
I think a better approach would be
HasWeirdOrd X
which has derived total ordering impls
What's the weird ord here?
Mario Carneiro (Dec 21 2023 at 11:40):
none < some k
in this case
Wrenna Robson (Dec 21 2023 at 11:40):
Right
Mario Carneiro (Dec 21 2023 at 11:40):
it might not even be a LT
implementation, I think RBMap uses compare
Eric Wieser (Dec 21 2023 at 11:41):
Maybe the answer here is docs#compare gets to have the weird order
Wrenna Robson (Dec 21 2023 at 11:41):
compare
is interesting. Does it need total ordering?
Eric Wieser (Dec 21 2023 at 11:41):
Since it can't agree with le / lt anyway unless the order is linear
Mario Carneiro (Dec 21 2023 at 11:41):
if we do that though then a lot of LawfulOrd
instances go out the window
Mario Carneiro (Dec 21 2023 at 11:42):
(and it might also be confusing)
Eric Wieser (Dec 21 2023 at 11:42):
Do they? docs#LawfulOrd is never true on a non-linear order ,is it?
Mario Carneiro (Dec 21 2023 at 11:42):
right, but if we put a linear order whenever there is a cmp then of course it will be lawful
Wrenna Robson (Dec 21 2023 at 11:42):
Yeah, one of the odd things here is that baked into the very definition of Ordering
is an assumption of totality
Wrenna Robson (Dec 21 2023 at 11:43):
One could imagine a type that had INC along with LT, EQ, and GT.
Mario Carneiro (Dec 21 2023 at 11:43):
you would not have a LawfulOrd instance unless you have a cmp anyway
Wrenna Robson (Dec 21 2023 at 11:43):
... Option (Ordering), if you will
Eric Wieser (Dec 21 2023 at 11:43):
Mario Carneiro said:
if we do that though then a lot of
LawfulOrd
instances go out the window
I don't think this typeclass even exists?
Mario Carneiro (Dec 21 2023 at 11:43):
no it doesn't, our metatheory around this area is in shambles in part because of the issues being discussed here
Eric Wieser (Dec 21 2023 at 11:43):
LinearOrder
is a candidate for it, which has the compatibility requirements
Wrenna Robson (Dec 21 2023 at 11:44):
Incidentally Option Ordering
is a great example, perhaps the prototypical example, of somewhere where the incomparable ordering is appropriate.
Mario Carneiro (Dec 21 2023 at 11:44):
I think the main relevant issue is lean4#1777
Eric Wieser (Dec 21 2023 at 11:44):
This solution looks like it works to me:
- On linearly ordered types, Lt, Le, cmp all agree (and we have a lawful instance that declares this)
- On partially-ordered types, cmp is the "most canonical" lexicographic linear order, which is independent of
<
and<=
Eric Wieser (Dec 21 2023 at 11:45):
Sure, it's a bit confusing that cmp can disagree with le/lt, but that seems like precisely the design requirement to put things with a partial order in an rbmap
Mario Carneiro (Dec 21 2023 at 11:46):
might be nice to have at least some partial agreement like x <= y -> (cmp x y).isLE
Eric Wieser (Dec 21 2023 at 11:46):
I think that one is fairly easy to keep
Eric Wieser (Dec 21 2023 at 11:47):
Mario Carneiro said:
I think the main relevant issue is lean4#1777
I don't know if I agree with this feature request; this feels like a problem for downstream code (std/mathlib) to deal with, not a core issue
Wrenna Robson (Dec 21 2023 at 11:47):
Would this mean that Option was free to have the incomparable ordering without breaking things?
Mario Carneiro (Dec 21 2023 at 11:47):
well it's in core in part because Ord
is in core
Mario Carneiro (Dec 21 2023 at 11:47):
I think we could just remove it?
Mario Carneiro (Dec 21 2023 at 11:47):
and relocate it to std
Eric Wieser (Dec 21 2023 at 11:47):
Well, OfNat
is in core and so is HAdd
, but that doesn't mean we need core to enforce 0 + x = x
Wrenna Robson (Dec 21 2023 at 11:48):
Presumably the rationale for things being in core is "this really is necessary to even have a programming language at all".
Mario Carneiro (Dec 21 2023 at 11:48):
well some of those things are in std too
Wrenna Robson (Dec 21 2023 at 11:48):
I'm not entirely sure I understand the user who would not use std4 but.
Eric Wieser (Dec 21 2023 at 11:48):
So why do we need it to enforce lawfulness of Ord
and LT
? To me, keeping Ord
as the raw notation class seems sensible, and Std should be building lawfulness on top of the notation classes
Mario Carneiro (Dec 21 2023 at 11:48):
not lawfulness, it just provides both operations
Eric Wieser (Dec 21 2023 at 11:49):
Wrenna Robson said:
Presumably the rationale for things being in core is "this really is necessary to even have a programming language at all".
My interpretation of this is "this is really necessary to _write_ the programming language itself"
Mario Carneiro (Dec 21 2023 at 11:49):
that way you have a one stop shop for assuming you have an ordered type
Mario Carneiro (Dec 21 2023 at 11:50):
mathlib understands the value of this very well but in lean4 programming mode we have 3 to 6 different ways to assume ordering on a type used in various combinations
Wrenna Robson (Dec 21 2023 at 11:50):
Ghastly.
Eric Wieser (Dec 21 2023 at 11:51):
Mario Carneiro said:
mathlib understands the value of this very well but in lean4 programming mode we have 3 to 6 different ways to assume ordering on a type used in various combinations
Does mathlib have any typeclasses that provide a bundle of data with no lawfulness?
Mario Carneiro (Dec 21 2023 at 11:51):
from what I can tell Ord
is used exactly 0 times in lean core for reasons other than deriving Ord
instances
Mario Carneiro (Dec 21 2023 at 11:51):
No, but that's not the point. In math mode of course you want lawfulness, in programming mode the lawfulness is in our hearts
Mario Carneiro (Dec 21 2023 at 11:52):
the point is that in mathlib you write LinearOrder
and get < and <= and compare and min and max, etc, rather than having that as 5 different typeclass arguments
Wrenna Robson (Dec 21 2023 at 11:54):
"the lawfulness is in our hearts" is very funny to me
Wrenna Robson (Dec 21 2023 at 11:54):
It do be like that
Eric Wieser (Dec 21 2023 at 11:58):
Ah, so the compromise you're proposing is that the lawfulness in our hearts become the weaker x <= y -> (cmp x y).isLE
and x = y -> (cmp x y).isEQ
, and then the operators can always coexist?
Eric Wieser (Dec 21 2023 at 11:58):
(that is, lawfulness means that cmp
always describes an order at least as strong as <
/<=
)
Mario Carneiro (Dec 21 2023 at 11:59):
yeah, there would be two LawfulOrd
like typeclasses in this case
Mario Carneiro (Dec 21 2023 at 12:00):
but Ord
itself would just give you the whole bundle
Eric Wieser (Dec 21 2023 at 12:00):
... and a warning that it is likely to not be quite as lawful as you might expect
Mario Carneiro (Dec 21 2023 at 12:00):
and it would be used for both linear and partial order cases
Eric Wieser (Dec 21 2023 at 12:00):
I think we still want a separate typeclass for compare
alone, to let you define things one piece at a time
Mario Carneiro (Dec 21 2023 at 12:01):
Usually when defining things one piece at a time it suffices to just have a standalone Foo.compare
function and use that as part of the construction
Mario Carneiro (Dec 21 2023 at 12:01):
it's often a good idea to do that anyway even if the typeclass just wraps it
Eric Wieser (Dec 21 2023 at 12:09):
The main downside in that approach is that if you state any lemmas about it, you have to state them again when you assemble the typeclass
Wrenna Robson (Dec 21 2023 at 12:11):
As I alluded to above, you could have a cmp?
which mapped into Option Ordering
.
Wrenna Robson (Dec 21 2023 at 12:12):
Like in a sense that might be what a partial order needs.
Wrenna Robson (Dec 21 2023 at 12:53):
Incidentally have submitted #9178 which is another small and easy PR around this issue.
Wrenna Robson (Dec 21 2023 at 12:55):
Is there a way to make a mathlib commit depend on a std4 commit?
Eric Wieser (Dec 21 2023 at 12:58):
Yes, you update the lake manifest to point at your std branch
Mario Carneiro (Dec 21 2023 at 12:58):
we should have a tag to track PRs which do that so that we don't accidentally merge them
Eric Wieser (Dec 21 2023 at 13:04):
Could we just have CI fail on anything other than master
in the lakefile?
Mario Carneiro (Dec 21 2023 at 13:45):
no, because we want these PRs to pass CI to justify merging the things they depend on
Mario Carneiro (Dec 21 2023 at 13:46):
We could have CI fail for the master/staging branch only, that would make bors reject it
Wrenna Robson (Dec 21 2023 at 15:02):
@Eric Wieser I wonder if there's a way to make a class that contains WithBot
, WithTop
, and whatever it is we call the thing with the incomparable whatsit, which might just be Option
.
Wrenna Robson (Dec 21 2023 at 15:03):
It occurs that there's lemmas that are always true for all of them - e.g.
lemma some_le_some_iff {a b : α} : some a ≤ some b ↔ a ≤ b :=
⟨le_of_some_le_some, some_le_some_of_le⟩
Where the proof is essentially the same for all of them.
Wrenna Robson (Dec 21 2023 at 15:04):
Wheras there are things that are only true in one of them.
Wrenna Robson (Dec 21 2023 at 15:04):
This to me feels like the kind of thing that a class is meant to handle.
Yaël Dillies (Dec 21 2023 at 15:06):
More like "some
is an OrderEmbedding
"
Eric Wieser (Dec 21 2023 at 15:07):
Note that each of WithBot
, WithTop
, and Option
have a different some
anyway, so what Yael describes is exactly the bit that is actually generalizable
Wrenna Robson (Dec 21 2023 at 15:07):
Sure.
Wrenna Robson (Dec 21 2023 at 15:09):
But the point is, there's a common structure there.
Wrenna Robson (Dec 21 2023 at 15:09):
Incidentally, why does OrderEmbedding.subtype
require Preorder
Yaël Dillies (Dec 21 2023 at 15:10):
because we don't really care about things weaker than preorders
Wrenna Robson (Dec 21 2023 at 15:10):
Ye-es.
Wrenna Robson (Dec 21 2023 at 15:10):
But it could just require LE
, right? It's just a notational truth.
Yaël Dillies (Dec 21 2023 at 15:12):
In that case, yes
Wrenna Robson (Dec 21 2023 at 15:12):
Essentially, I can say this:
def optionIsSomeOrderIso (α : Type*) [LE α] : { x : Option α // x.isSome } ≃o α where
toFun o := Option.get _ o.2
invFun x := ⟨some x, rfl⟩
left_inv _ := Subtype.eq <| Option.some_get _
right_inv _ := Option.get_some _ _
map_rel_iff' := get_le_get_iff_le _ _
Obviously I can do something similar with the embedding of some
. But in a sense it would be good to derive the latter from the former. Unfortunately for that...
def someOrderEmbedding (α : Type*) [Preorder α] : OrderEmbedding α (Option α) :=
RelEmbedding.trans (optionIsSomeOrderIso α).symm.toOrderEmbedding (OrderEmbedding.subtype _)
Wrenna Robson (Dec 21 2023 at 15:12):
You need Preorder.
Wrenna Robson (Dec 21 2023 at 15:14):
If you look at WithBot.some_le_some
, the WithBot version of what I cited above, it just needs LE
. So clearly you would want to do the same thing here.
Eric Wieser (Dec 21 2023 at 15:17):
This is in general a problem; if you make your morphisms assume any lawful structure, then you find that you can't use the morphisms to pull back / push forward structure
Wrenna Robson (Dec 21 2023 at 15:19):
Aye. Because this is the bit where their structure is in agreement I had hoped this wouldn't be an issue
Wrenna Robson (Dec 21 2023 at 15:19):
And you know, things like MulEquivClass
seem magic to me
Eric Wieser (Dec 21 2023 at 15:19):
(but if your morphisms don't assume any structure, then often you end up needing way more fields; group morphisms and monoid morphisms are the same, but one
/mul
/inv
morphisms and one
/mul
morphisms are different)
Wrenna Robson (Dec 21 2023 at 15:21):
Partially I just think it's things having differing levels of generality across the library - in this case, Monotone
is only defined on Preorders, even though it makes sense as a sentence (even if it has less meaning) for LE.
Wrenna Robson (Dec 21 2023 at 15:21):
But you could change it.
Wrenna Robson (Dec 21 2023 at 15:22):
Personally I think definitions should always be made with minimal assumptions.
Eric Wieser (Dec 21 2023 at 15:23):
So should we have separate MonoidHom
and GroupHom
in order to permit that? That creates massive amounts of extra boilerplate...
Wrenna Robson (Dec 21 2023 at 15:23):
I'm not sure I understand what that has to do with Monotone
...
Wrenna Robson (Dec 21 2023 at 15:23):
Always here should be understood to mean "not always, but often".
Wrenna Robson (Dec 21 2023 at 15:24):
I am not sure you would need GroupHom? That's actually an example of the kind of generality I think is good.
Eric Wieser (Dec 21 2023 at 15:24):
Always here should be understood to mean "not always, but often".
I don't think defining X
in terms of not X
is particularly transparent...
Wrenna Robson (Dec 21 2023 at 15:24):
?
Wrenna Robson (Dec 21 2023 at 15:25):
Oh I see - I mean I'm just being colloquial I guess.
Wrenna Robson (Dec 21 2023 at 15:25):
As a rule of thumb, one should always bend towards minimal assumptions for things, but sometimes that isn't necessary.
Wrenna Robson (Dec 21 2023 at 15:25):
In this case I was asking "can we have less boilerplate here somehow".
Yaël Dillies (Dec 21 2023 at 15:26):
And I would think this is pretty minimal in terms of boilerplate already.
Wrenna Robson (Dec 21 2023 at 15:26):
Also pointing out that it is mildly absurd that the assumptions for defining an OrderEmbedding are in fact less than that needed to define an OrderHom.
Yaël Dillies (Dec 21 2023 at 15:26):
Agreed. I'm happy to merge a PR to change it to Preorder
!
Wrenna Robson (Dec 21 2023 at 15:26):
Ha!
Wrenna Robson (Dec 21 2023 at 15:27):
But presumably not to go in the other direction?
Yaël Dillies (Dec 21 2023 at 15:27):
No, I wouldn't really see the point
Wrenna Robson (Dec 21 2023 at 15:29):
Hmm.
Wrenna Robson (Dec 21 2023 at 15:32):
I think in my view they're equally pointless - so I don't really understand why you'd be happy to do one but not the other.
Wrenna Robson (Dec 21 2023 at 15:33):
(I am perfectly content for pointless things to happen.)
Wrenna Robson (Dec 21 2023 at 15:35):
And, indeed, if I look at, say, the structure of WithBot.lean
, I can see a clear distinction between LE
and LT
assumptions and Preorder ones.
Wrenna Robson (Dec 21 2023 at 17:46):
I have PR'd #9181, just to get something in there. But the core issue of what the solution should be is not resolved.
Wrenna Robson (Dec 21 2023 at 17:47):
I have also summarised the above discussion - @Mario Carneiro I haven't gone into all the detail you gave but I've tried to represent your position fairly. Of course, if you feel there are important points to add, please do do so.
Wrenna Robson (Dec 21 2023 at 22:46):
@Joe Hendrix if you're interested in the context of that PR to std, it's here.
Wrenna Robson (Dec 21 2023 at 22:53):
#9181 tries to summarise the situation. Unfortunately there are a few moving parts.
Wrenna Robson (Dec 21 2023 at 22:56):
If we end up removing Rel and not putting StrictRel into standard, I suspect I will add them to #9181!
Wrenna Robson (Dec 21 2023 at 23:07):
Amused that we are solving all the issues with this being spread across three places by just adding everything into Mathlib.
Mario Carneiro (Dec 21 2023 at 23:08):
I feel like that has historically been the solution to quite a lot of problems
Wrenna Robson (Dec 21 2023 at 23:08):
And the cause!
Wrenna Robson (Dec 21 2023 at 23:08):
It's interesting because presumably these were deliberately added to std4? But I agree they taste more mathsy.
Mario Carneiro (Dec 21 2023 at 23:09):
they were part of the initial mathlib import of these basic files
Wrenna Robson (Dec 21 2023 at 23:09):
Right.
Wrenna Robson (Dec 21 2023 at 23:11):
Well, Rel and StrictRel would fit well into Data/Option/Order when it exists though we still haven't entirely resolved this issue of what should actually happen to Option by default.
Mario Carneiro (Dec 21 2023 at 23:11):
they may not be defined like that though
Mario Carneiro (Dec 21 2023 at 23:12):
best wait until we have the rest of it together
Patrick Massot (Dec 21 2023 at 23:12):
Wrenna Robson said:
Amused that we are solving all the issues with this being spread across three places by just adding everything into Mathlib.
This strategy served us extremely well in the past. Now we are trying to move away from this. There are good reasons to do that, but the cost is huge.
Eric Wieser (Dec 21 2023 at 23:17):
Mario Carneiro said:
best wait until we have the rest of it together
Is there any reason not to have (in mathlib) Rel, StrictRel, and the lemmas saying that if R
is transitive then so is Rel R
etc? I think the contention in this thread is about canonical orders, not arbitrary relations
Mario Carneiro (Dec 21 2023 at 23:17):
I think those are fine theorems to have in mathlib
Mario Carneiro (Dec 21 2023 at 23:18):
without a use case in std they are just dead weight
Eric Wieser (Dec 21 2023 at 23:18):
Ah, so you mean "wait until the rest is together before upstreaming anything to std"?
Mario Carneiro (Dec 21 2023 at 23:19):
we should have a coherent strategy for how all these theorems are to be used together to improve the general usability of lean qua programming language
Wrenna Robson (Dec 21 2023 at 23:19):
Indeed.
Eric Wieser (Dec 21 2023 at 23:20):
But this isn't a prerequisite for (partial?) inclusion in mathlib
Eric Wieser (Dec 21 2023 at 23:20):
(maybe it is a prerequisite for the global instance being proposed)
Mario Carneiro (Dec 21 2023 at 23:21):
indeed not, the mathlib bar is a bit closer to "it's true and potentially useful"
Wrenna Robson (Dec 21 2023 at 23:21):
As I say, this all started because I had some function I'd defined to Option (Fin n), because having it defined to Fin n with junk values was giving me a need to have NeZero n everywhere. Semantically, Option is correct. But then I wanted certain ordering theorems to be true - essentially think "this is a partial function, but when it has values, these nice inequalities are true".
Wrenna Robson (Dec 21 2023 at 23:22):
This was in the context of my real actual work I've been doing (well - actually it was in a refactor to SuccAbove I was looking at that had come from that - the point is it was me actually using Lean for a real purpose - at the end of the day, trying to verify this particular subroutine in some cryptography - so I am here wearing the hat, partially, of Real Actual User).
Mario Carneiro (Dec 21 2023 at 23:23):
right, that sounds like sufficient grounds to get it in mathlib
Eric Wieser (Dec 21 2023 at 23:24):
I think you should split #9181 into the bit that doesn't conflict with the core instance, and the bit that does
Wrenna Robson (Dec 21 2023 at 23:24):
Indeed. And I'd quite like this default order to be on Option, because for the interpretation of Option as "partial function codomain", if you see what I mean, you kinda really don't want none to accidentally mean anything.
Wrenna Robson (Dec 21 2023 at 23:25):
Ah, so just the LE instance, and then the LT part and beyond?
Mario Carneiro (Dec 21 2023 at 23:26):
I think by std standards this mainly motivates not having a LE or LT instance on Option at all
Wrenna Robson (Dec 21 2023 at 23:26):
That's reasonable. As I say I do think having the core instance is not unreasonable - it is just unfortunate that a) it has zero API, b) we re-implement that as WithBot.
Mario Carneiro (Dec 21 2023 at 23:26):
let downstream users decide what they want to do with it
Wrenna Robson (Dec 21 2023 at 23:26):
Yes, I think that would be the correct choice for std.
Eric Wieser (Dec 21 2023 at 23:26):
As a reminder Mario, the problem is that core has already decided for us
Mario Carneiro (Dec 21 2023 at 23:26):
that one seems to be on its way out, I don't think anyone has objected to that
Wrenna Robson (Dec 21 2023 at 23:27):
From a mathlib point of view you know my view.
Wrenna Robson (Dec 21 2023 at 23:27):
But I'm in total agreement also that this is a better choice for maths than for programmers.
Mario Carneiro (Dec 21 2023 at 23:27):
it was added in very early lean 4, if it's not used by now then I doubt anyone will defend it
Eric Wieser (Dec 21 2023 at 23:28):
Mario Carneiro said:
that one seems to be on its way out, I don't think anyone has objected to that
I think the context for lean4#3100 has grown so large there's a serious chance of the core PR being ignored because the benefit is not worth reading this zulip thread to work out what the consensus is
Wrenna Robson (Dec 21 2023 at 23:28):
2018 I think?
Joe Hendrix (Dec 21 2023 at 23:28):
@Wrenna Robson Thanks for mentioning this thread. If your code is publicly is available, I'd be interested in taking a look to get more context.
Wrenna Robson (Dec 21 2023 at 23:28):
It is. #9181 contains a summary of the relevant PRs and the discussion so you don't have to read scrollback.
Wrenna Robson (Dec 21 2023 at 23:29):
I was trying to obey the contribution guidelines of "don't expect everyone to have to read Zulip" <_<
Joe Hendrix (Dec 21 2023 at 23:29):
@Wrenna Robson Oh, I meant the crypto code.
Wrenna Robson (Dec 21 2023 at 23:29):
Oh!
Wrenna Robson (Dec 21 2023 at 23:31):
Well, that's a whole other thing. Technically my project is not cryptography per se - I've been working on a verification of Classic McEliece's representation of permutations as bitvectors, extending prior work by DJB. In particular this necessitated some annoying to prove theorems about succAbove and predAbove (... which I think might actually be the simplicial identities...) and that prompted an attempt at a refactor of that.
Joe Hendrix (Dec 21 2023 at 23:31):
Perhaps BitVec n
(or some other type than Option (Fin n)
would be useful). I think the downside of a type of like Option
is that none
can mean virtually anything.
Wrenna Robson (Dec 21 2023 at 23:31):
It's the XKCD sharks comic.
Wrenna Robson (Dec 21 2023 at 23:32):
In this case, Option (Fin n) is being used in the sense of, I have a map from pairs of Fin (n + 1) to Fin n, but it only really applies to distinct pairs.
Wrenna Robson (Dec 21 2023 at 23:33):
It's actually precisely the existing docs#finSuccEquiv'
Wrenna Robson (Dec 21 2023 at 23:34):
Which you'll note maps to Option.
Wrenna Robson (Dec 21 2023 at 23:35):
I agree that none can mean virtually anything, but the interpretation of Option I favour, the one we all learn metaphorically on our grandmother's knee, right, is "computations that might fail".
Wrenna Robson (Dec 21 2023 at 23:37):
BUT - other choices are available, I get that.
Joe Hendrix (Dec 21 2023 at 23:37):
Thanks for the context. It's being used as something like a set with at most one element.
Wrenna Robson (Dec 21 2023 at 23:38):
Yes - bit like how List can mean "computations which can have a variable number of outputs".
Joe Hendrix (Dec 21 2023 at 23:41):
I think keeping the definitions and theorems in Mathlib makes sense to me, but the context is helpful.
Wrenna Robson (Dec 21 2023 at 23:41):
Indeed. The debate has been about whether or not there should be any kind of order on Option at all and if so what it should be.
Wrenna Robson (Dec 22 2023 at 08:12):
@Eric Wieser I'm not sure about splitting that PR until we've obtained some consensus about the holistic plan.
Wrenna Robson (Dec 22 2023 at 13:26):
Unfortunately I don't really know how to rework my core issue or PR so that the maintainers will spend any time on it. I would hope it would be an easy choice for them.
Wrenna Robson (Dec 22 2023 at 13:26):
But that requires them to actually look at it.
Last updated: May 02 2025 at 03:31 UTC