Skip to content

Fix maximumBy comparison - #180

Merged
dolio merged 3 commits into
haskell:masterfrom
basile-henry:master
Jul 23, 2017
Merged

Fix maximumBy comparison#180
dolio merged 3 commits into
haskell:masterfrom
basile-henry:master

Conversation

@basile-henry

@basile-henrybasile-henry commented Jul 17, 2017

Copy link
Copy Markdown
Contributor

maximumBy for vectors does not behave like the list version:

> maximumBy (comparing snd) $zip [0..10::Int] (repeat'a')
(10,'a')
>V.maximumBy (comparing snd) .V.fromList $zip [0..10::Int] (repeat'a')
(0,'a')

This pull request fixes this issue by checking for GT rather than LT which changes the behavior in the EQ case.

`maximumBy` for vectors does not behave like the list version:
```
> maximumBy (comparing snd) $ zip [0..10 :: Int] (repeat 'a')
(10,'a')
> V.maximumBy (comparing snd) . V.fromList $ zip [0..10 :: Int] (repeat 'a')
(0,'a')
```
This commit fixes this issue by checking for `GT` rather than `LT` which changes the behavior in the `EQ` case.
@cartazio

cartazio commented Jul 17, 2017 via email

Copy link
Copy Markdown
Contributor

@basile-henry

Copy link
Copy Markdown
ContributorAuthor

@cartazio I am not sure how version changes have been handle so far with the vector package. The type signature of maximumBy does not change so I'd be tempted to just call it a patch. However it is possible some use cases rely on the old implementation.
As far as I am concerned, I'd happily wait until the next major version bump for this to be added just to be on the safe side. I'll be using the patch for my own projects in the meantime.

@cartazio

cartazio commented Jul 17, 2017 via email

Copy link
Copy Markdown
Contributor

@basile-henry

basile-henry commented Jul 21, 2017

Copy link
Copy Markdown
ContributorAuthor

@cartazio I don't believe there is a difference in performance between this version and the previous one. The result of a comparison does not affect how much of the vector is used: maximumBy has to visit every single element in the vector regardless of the outcome of a comparison.

I would like to point out that the behaviour of maximumBy and minimumBy for lists is a bit odd:

> maximumBy (comparing snd) $zip [0..10::Int] (repeat'a')
(10,'a')
> minimumBy (comparing snd) $zip [0..10::Int] (repeat'a')
(0,'a')

maximumBy returns the last element which is a maximum, whereas minimumBy returns the first minimum element.

I believe this comes from the way max and min are implemented by default in Data.Ord:

-- These two default methods use '<=' rather than 'compare'-- because the latter is often more expensivemax x y =if x <= y then y else x
min x y =if x <= y then x else y

max returns the second argument in case of equality, whereas min returns the first one.

@dolio

Copy link
Copy Markdown
Contributor

Yeah, it does require a major bump, since it technically changes the behavior of an exported function.

Anyhow, looks good.

@dolio
dolio merged commit b3c922a into haskell:masterJul 23, 2017
@glguy

Copy link
Copy Markdown
Member

Neither the Haskell Report's maximumBy nor Vector's appear to document any promises about the behavior when two elements are different by compare to EQ. If vector package is going to make a version bump for this change, should the haddock comment include some mention of what the guaranteed behavior is?

@basile-henry

Copy link
Copy Markdown
ContributorAuthor

Writing documentation about the behavior in the EQ case makes sense. Are you thinking of something along the lines of (modified version of the Data.List.maximumBy docs) :

--| The largest element of a non-empty vector with respect to the given comparison function.---- __Note__: In the case where several elements can be considered maximum, the last one is returned.

I was thinking that maybe we shouldn't document this behavior in haddock but rather only as a comment in the code. Documenting it in haddock would tell the user of the library that they can rely on a specific implementation of this edge case.

I don't think this particular implementation makes more sense than any other one. The only reason I wanted to implement it like this is so it would match the current (also unspecified) behavior of maximumBy fromData.List.

The solution would be to either document the edge case behavior in both base and vector or in neither. In the second case, the guaranty the vector package offers is to have the same behavior as base even in some unspecified (to the user of the library) cases.

I am sure similar questions about documentation and specifications have arised in the Haskell ecosystem before. I am pretty new to Haskell library contributions, so how is this usually handled?

@ShimuuarShimuuar mentioned this pull request Jan 31, 2020
Shimuuar added a commit to Shimuuar/vector that referenced this pull request Apr 12, 2020
lehins pushed a commit to lehins/vector that referenced this pull request Jun 5, 2020
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@basile-henry@cartazio@dolio@glguy