-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Data.List.compareLength #257
Comments
|
No, I cannot find any examples for
Prior art in |
Another function whose name I think we should have in the backs of our minds when considering this proposal is the one checking whether the length of a list is at least a particular number, and the two-list variants of that one (i.e., the extensions of Edit: similarly, less than and greater than. |
similar: A simple implementation would be:
|
I'm not sure I want to bikeshed naming of other similar functions right now. There is consistent prior art to use With regards to lazy analogs of
compareLength1 :: forall {a}. [a] -> Int# -> Ordering
compareLength1
= \ (@a_s13T) (ds_s13L :: [a_s13T]) (ww_s13O :: Int#) ->
case ds_s13L of {
[] ->
case <# 0# ww_s13O of {
__DEFAULT ->
case ww_s13O of {
__DEFAULT -> GT;
0# -> EQ
};
1# -> LT
};
: y_a13H ys_a13I ->
case ># 0# ww_s13O of {
__DEFAULT -> compareLength1 ys_a13I (-# ww_s13O 1#);
1# -> GT
}
} |
This seems like a solid improvement and follows prior art. I'm in favor. |
What should be the result of For In other words, should we be lazy in the list if the length is negative? |
There seem to be three sensible functions with this name:
and no clear winner. Of I guess you want to save an import of a utility library. However the price to pay is to restrict your code to a recent version GHC. I would not add such a function to |
I'm finding it hard to understand where this would be used. Could someone point to examples in the wild? |
I don't remember the names of the functions, or the module in which they're defined, but GHC uses several such functions. Vague recollection: try |
The And what about generalising to |
As @treeowl mentions, GHC uses: lengthAtMost :: [a] -> Int -> Bool
lengthIsNot :: [a] -> Int -> Bool
lengthIs :: [a] -> Int -> Bool
lengthAtLeast :: [a] -> Int -> Bool
lengthExceeds :: [a] -> Int -> Bool
lengthLessThan :: [a] -> Int -> Bool
compareLength :: [a] -> [b] -> Ordering
equalLength :: [a] -> [b] -> Bool These are used to avoid forcing lazy lists or to avoid traversing potentially long lists. |
@meooow25 A weak precedent is that > take 0 undefined
[] Ideally I'd love to have
@thielema this seems to be a general argument against adding anything ever to I want @tomjaguarpaw this proposals stems from our discussion with @noughtmare at kowainik/stan#550. |
@Bodigrim that makes sense. But the proposed implementation needs some changes if it is to be lazy. |
Since GHC uses lengthGuess :: [a] -> Int -> Ordering
-- or
guessLength :: [a] -> Int -> Ordering
compareLength :: [a] -> [b] -> Ordering |
I still like |
@sjoerdvisscher excellent questions!
Rules rewriting In theory users might use
While the definition above indeed works for any Note that introduction of a monomorphic I think a good addition to the proposal would be
It would be quite attractive for two reasons:
Yet I imagine that in the majority of cases |
@Bodigrim do you have an MR prepared for this function? More than once since you brought it up have I wished we already had it in |
I've updated the proposal and linked the MR. |
I suggest a couple of changes. compareLength :: [a] -> Int -> Ordering
compareLength xs n
| n < 0 = GT
- | otherwise = foldr (\_ f m -> if 0 > m then GT else f (m - 1)) (compare 0) xs n
+ | otherwise = foldr (\_ f m -> if m > 0 then f (m - 1) else GT) (\m -> if m > 0 then LT else EQ) xs n
|
@meooow25 could you possibly elaborate what's improved by the suggested change? |
Sure,
|
`compareLength xs n` is a safer and faster alternative to `compare (length xs) n`. The latter would force and traverse the entire spine (potentially diverging), while the former traverses as few elements as possible. The implementation is carefully designed to maintain as much laziness as possible. As per haskell/core-libraries-committee#257
@meooow25 thanks, I've update the MR. Does it look good now? |
Looks good, thanks! I am wondering if it would be useful to |
My preference is to apply |
I'll trigger a vote soon unless there are more comments / suggestions. |
Dear CLC members, let's vote on the proposal to add @hasufell @velveteer @mixphix @tomjaguarpaw @angerman @parsonsmatt +1 from me, unsurprisingly. |
+1, anything that reduces |
+1 |
`compareLength xs n` is a safer and faster alternative to `compare (length xs) n`. The latter would force and traverse the entire spine (potentially diverging), while the former traverses as few elements as possible. The implementation is carefully designed to maintain as much laziness as possible. As per haskell/core-libraries-committee#257
@mixphix @hasufell @tomjaguarpaw @angerman just a gentle reminder to vote. |
+1 |
2 similar comments
+1 |
+1 |
Thanks all, that's enough votes to approve. |
`compareLength xs n` is a safer and faster alternative to `compare (length xs) n`. The latter would force and traverse the entire spine (potentially diverging), while the former traverses as few elements as possible. The implementation is carefully designed to maintain as much laziness as possible. As per haskell/core-libraries-committee#257
`compareLength xs n` is a safer and faster alternative to `compare (length xs) n`. The latter would force and traverse the entire spine (potentially diverging), while the former traverses as few elements as possible. The implementation is carefully designed to maintain as much laziness as possible. As per haskell/core-libraries-committee#257
`compareLength xs n` is a safer and faster alternative to `compare (length xs) n`. The latter would force and traverse the entire spine (potentially diverging), while the former traverses as few elements as possible. The implementation is carefully designed to maintain as much laziness as possible. As per haskell/core-libraries-committee#257
`compareLength xs n` is a safer and faster alternative to `compare (length xs) n`. The latter would force and traverse the entire spine (potentially diverging), while the former traverses as few elements as possible. The implementation is carefully designed to maintain as much laziness as possible. As per haskell/core-libraries-committee#257
There is a discussion what to do with the existing |
Let's extend
Data.List
/Data.List.NonEmpty
with new functions:The idea is that
compareLength xs n
serves as a safer and faster alternative tocompare (length xs) n
. Similarly, it's better to writecompareLength xs 10 == LT
instead oflength xs < 10
. Whilelength
would force and traverse the entire spine ofxs
(which could even diverge ifxs
is infinite),compareLength
traverses at mostn
elements to determine its result.(This deficiency of
length
has been long recognised by warning STAN-0103 instan
)Prior art:
The choice of name
compareLength
follows precedents in prior art, but also it's most natural to name a better version of(compare .) . length
ascompareLength
.MR can be found at https://gitlab.haskell.org/ghc/ghc/-/merge_requests/12822
How about generalizing from
[a]
andNonEmpty a
to anyFoldable
?While the definition above uses only
foldr
and indeed works for anyFoldable
, it's hard to tell whethercompareLength
is better than(compare .) . length
for a givenFoldable
or no. Iflength
is O(1) thencompare (length xs) n
is faster thancompareLength xs n
which is O(n). Thus the proposal argues for addingcompareLength
only to containers for whichlength
is known to be inefficient.Having the monomorphic
Data.List.compareLength
does not preclude anyone from raising a proposal to addData.Foldable.compareLength
or whatever they fancy to argue for.How about generalizing from
Int
to anyNum
?I imagine that in the majority of cases
n
incompareLength xs n
is a literal constant, so the change would force everyone to write an explicit type as incompareLength xs (10 :: Int)
, which will get very annoying soon. So let's stick to the usual convention ofInt
for length/indexing inData.List
.One could argue for
genericlengthCompare xs n
, polymorphic byn
similar to the existinggenericLength
, but again, let me leave it to others to propose.How about adding a rewrite rule changing
compare (length xs) n
tocompareLength xs n
?Such rule could affect semantics, making diverging programs terminate. While I'd expect such change to be a desirable one in the majority of cases, I'd rather leave it to a (potential) subsequent proposal.
The text was updated successfully, but these errors were encountered: