Skip to content
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

Match nub* functions with Array #179

Merged
merged 24 commits into from
Jan 25, 2021
Merged

Conversation

milesfrain
Copy link
Contributor

@milesfrain milesfrain commented Dec 18, 2020

Fixes #178

  • Data.List
  • Data.List.Lazy
  • Data.List.NonEmpty

Edit: Now with nub/nubBy for lazy list too.


Old comment:

Since Data.List.Lazy doesn't have sort yet, I don't think it's in the scope of this PR to add the optimized Ord-based nub/nubBy to that module. It will just be stuck with nubEq/nubByEq for now.

If we do want to add sort to Data.List.Lazy (in another PR), we might be able to find some inspiration from Haskell's implementation.

src/Data/List.purs Outdated Show resolved Hide resolved
src/Data/List.purs Outdated Show resolved Hide resolved
test/Test/Data/List.purs Outdated Show resolved Hide resolved
src/Data/List.purs Outdated Show resolved Hide resolved
src/Data/List.purs Outdated Show resolved Hide resolved
bower.json Outdated Show resolved Hide resolved
src/Data/List.purs Outdated Show resolved Hide resolved
src/Data/List.purs Outdated Show resolved Hide resolved
src/Data/List.purs Outdated Show resolved Hide resolved
src/Data/List.purs Outdated Show resolved Hide resolved
src/Data/List.purs Show resolved Hide resolved
test/Test/Data/List.purs Outdated Show resolved Hide resolved
test/Test/Data/List.purs Outdated Show resolved Hide resolved
test/Test/Data/List.purs Outdated Show resolved Hide resolved
@milesfrain
Copy link
Contributor Author

If this looks good for Data.List, then I'll apply the same changes to Lazy and NonEmpty.

I'm also thinking of refactoring the test code and extracting common material, so we don't have as much copy-paste going on between the three files.

I assume circular dependencies prevent us from upgrading the test framework to something that prints more info upon failures. I'm a fan of test-unit.

@hdgarrood
Copy link
Contributor

Yes, everything is very basic in the core libraries for this reason. test-unit is not an option both because of circular dependencies and because there is a policy that core libraries cannot depend on non-core libraries.

@hdgarrood
Copy link
Contributor

This looks great so far 👍

@milesfrain milesfrain marked this pull request as ready for review January 6, 2021 23:55
@JordanMartinez
Copy link
Contributor

This looks good to me!

Copy link
Member

@thomashoneyman thomashoneyman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking care of this! Minor formatting suggestions, but otherwise 👍 from me.

src/Data/List.purs Outdated Show resolved Hide resolved
src/Data/List.purs Outdated Show resolved Hide resolved
Co-authored-by: Thomas Honeyman <admin@thomashoneyman.com>
src/Data/List/Lazy.purs Show resolved Hide resolved
test/Test/Data/List.purs Outdated Show resolved Hide resolved
nubBy eq' (x : xs) = x : nubBy eq' (filter (\y -> not (eq' x y)) xs)
nubByEq :: forall a. (a -> a -> Boolean) -> List a -> List a
nubByEq _ Nil = Nil
nubByEq eq' (x : xs) = x : nubByEq eq' (filter (\y -> not (eq' x y)) xs)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was never stack-safe. Reported in #194

let { found, result: s' } = insertAndLookupBy p a s
in if found
then step (go s' as)
else Cons a (go s' as)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't look stack safe, but I don't know of a good way to fix it. The stack-safety strategy for strict nubBy involved reversing the final result, but that can't be done here with infinite lazy lists. Reported in #194

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is mostly stack-safe, because it's the caller's responsibility to force the thunks and most of the recursive calls are deferred. However, there could potentially be enough duplicate elements in a row to blow the stack (since we do recursively force thunks in that case).

CHANGELOG.md Outdated
Comment on lines 7 to 11
Breaking changes:
- Convert `nub`/`nubBy` to use ordering, rather than equality (#179)

New features:
- Add `nubEq`/`nubByEq` (#179)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could have alternatively written this as:

Breaking changes:

New features:

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the way you've formulated it in the changelog currently.

@@ -332,8 +334,15 @@ testListLazy = do
assert $ nub (l [1, 2, 2, 3, 4, 1]) == l [1, 2, 3, 4]

log "nubBy should remove duplicate items from the list using a supplied predicate"
let nubPred = \x y -> if odd x then false else x == y
assert $ nubBy nubPred (l [1, 2, 2, 3, 3, 4, 4, 1]) == l [1, 2, 3, 3, 4, 1]
let nubPred = compare `on` Array.length
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a test which ensures that nub behaves sensibly on infinite lists please? Perhaps

log "nub should not consume more of the input list than necessary"
assert $ (take 3 $ nub $ cycle $ l [1,2,3]) == l [1,2,3]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this test be applied to all nub* functions, or just nub? I just added the single test.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it’s worth doing it for nub and nubEq but we probably don’t need it for the *By variants, as if it works for nub it’ll probably work for nubBy too.

Comment on lines +21 to +25
- Fixed Lazy List docs where original list is returned instead of Nothing (#169)
- Migrated to GitHub Actions (#177)
- Changed `foldM` type signature to more closely match `foldl` (#165)
- Improved `foldr` performance on large lists (#180)
- Generated changelog and add PR template (#187)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe consensus for changelog is to use past tense

@thomashoneyman
Copy link
Member

I believe this PR can be merged, but I think it would be good for @hdgarrood and/or @MonoidMusician to have one more glance over it before we do.

@MonoidMusician
Copy link
Contributor

Looks good to me! Did a couple more tests in the repl just to verify

Copy link
Contributor

@hdgarrood hdgarrood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me 👍

@thomashoneyman thomashoneyman merged commit f5b771e into purescript:master Jan 25, 2021
@milesfrain milesfrain deleted the nub-ord branch April 23, 2021 03:32
Sign up for free to 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.

Match nub* functions with Array
5 participants