diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 43d2897..c69237a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,10 +13,12 @@ jobs: - uses: actions/checkout@v2 - uses: purescript-contrib/setup-purescript@main + with: + purescript: "unstable" - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v2 with: - node-version: "12" + node-version: "14.x" - name: Install dependencies run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 203f0dd..db8662b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,37 @@ Notable changes to this project are documented in this file. The format is based Breaking changes: +New features: + +Bugfixes: + +Other improvements: + +## [v7.0.0](https://github.com/purescript/purescript-lists/releases/tag/v7.0.0) - 2022-04-27 + +Breaking changes: +- Update project and deps to PureScript v0.15.0 (#203 by @JordanMartinez) +- Drop deprecated `MonadZero` instance (#205 by @JordanMartinez) +- Drop deprecated `group'` and `mapWithIndex` (#206 by @JordanMartinez) +- Change `groupAllBy` to use a comparison function (#191) + +New features: + +Bugfixes: + +Other improvements: + +## [v6.1.0](https://github.com/purescript/purescript-lists/releases/tag/v6.1.0) - 2022-02-22 + +Breaking changes: + New features: - Added `cons` for `Lazy.NonEmptyList` (#143 by @matthewleon) Bugfixes: Other improvements: +- Fix ad-hoc usage of case expression (#202 by @JordanMartinez) ## [v6.0.1](https://github.com/purescript/purescript-lists/releases/tag/v6.0.1) - 2021-04-19 @@ -29,7 +54,7 @@ Breaking changes: New features: - Added `nubEq`/`nubByEq` (#179) -- Added `groupAllBy` (#182, #191) +- Added `groupAllBy` (#182) - Added `Eq1` and `Ord1` instances to `NonEmptyList` and `LazyNonEmptyList` (#188) Bugfixes: diff --git a/bower.json b/bower.json index ac63d1a..62188ce 100644 --- a/bower.json +++ b/bower.json @@ -19,24 +19,23 @@ "package.json" ], "dependencies": { - "purescript-bifunctors": "^5.0.0", - "purescript-control": "^5.0.0", - "purescript-foldable-traversable": "^5.0.0", - "purescript-lazy": "^5.0.0", - "purescript-maybe": "^5.0.0", - "purescript-newtype": "^4.0.0", - "purescript-nonempty": "^6.0.0", - "purescript-partial": "^3.0.0", - "purescript-prelude": "^5.0.0", - "purescript-tailrec": "^5.0.0", - "purescript-tuples": "^6.0.0", - "purescript-unfoldable": "^5.0.0" + "purescript-bifunctors": "^6.0.0", + "purescript-control": "^6.0.0", + "purescript-foldable-traversable": "^6.0.0", + "purescript-lazy": "^6.0.0", + "purescript-maybe": "^6.0.0", + "purescript-newtype": "^5.0.0", + "purescript-nonempty": "^7.0.0", + "purescript-partial": "^4.0.0", + "purescript-prelude": "^6.0.0", + "purescript-tailrec": "^6.0.0", + "purescript-tuples": "^7.0.0", + "purescript-unfoldable": "^6.0.0" }, "devDependencies": { - "purescript-arrays": "^6.0.0", - "purescript-assert": "^5.0.0", - "purescript-console": "^5.0.0", - "purescript-math": "^3.0.0", - "purescript-minibench": "^3.0.0" + "purescript-arrays": "^7.0.0", + "purescript-assert": "^6.0.0", + "purescript-console": "^6.0.0", + "purescript-minibench": "^4.0.0" } } diff --git a/package.json b/package.json index a4773ed..be00cb4 100644 --- a/package.json +++ b/package.json @@ -2,16 +2,15 @@ "private": true, "scripts": { "clean": "rimraf output && rimraf .pulp-cache", - "build": "pulp build -- --censor-lib --strict --censor-codes='UserDefinedWarning'", + "build": "pulp build -- --censor-lib --strict", "test": "pulp test", - "bench:build": "purs compile 'bench/**/*.purs' 'src/**/*.purs' 'bower_components/*/src/**/*.purs'", "bench:run": "node --expose-gc -e 'require(\"./output/Bench.Main/index.js\").main()'", "bench": "npm run bench:build && npm run bench:run" }, "devDependencies": { - "pulp": "^15.0.0", - "purescript-psa": "^0.8.0", + "pulp": "16.0.0-0", + "purescript-psa": "^0.8.2", "rimraf": "^3.0.2" } } diff --git a/src/Data/List.purs b/src/Data/List.purs index db9c1cd..8046afd 100644 --- a/src/Data/List.purs +++ b/src/Data/List.purs @@ -51,7 +51,6 @@ module Data.List , filterM , mapMaybe , catMaybes - , mapWithIndex , sort , sortBy @@ -68,7 +67,6 @@ module Data.List , span , group , groupAll - , group' , groupBy , groupAllBy , partition @@ -106,7 +104,6 @@ import Control.Monad.Rec.Class (class MonadRec, Step(..), tailRecM, tailRecM2) import Data.Bifunctor (bimap) import Data.Foldable (class Foldable, foldr, any, foldl) import Data.Foldable (foldl, foldr, foldMap, fold, intercalate, elem, notElem, find, findMap, any, all) as Exports -import Data.FunctorWithIndex (mapWithIndex) as FWI import Data.List.Internal (emptySet, insertAndLookupBy) import Data.List.Types (List(..), (:)) import Data.List.Types (NonEmptyList(..)) as NEL @@ -117,7 +114,6 @@ import Data.Traversable (scanl, scanr) as Exports import Data.Traversable (sequence) import Data.Tuple (Tuple(..)) import Data.Unfoldable (class Unfoldable, unfoldr) -import Prim.TypeError (class Warn, Text) -- | Convert a list into any unfoldable structure. -- | @@ -376,7 +372,7 @@ reverse = go Nil -- | -- | Running time: `O(n)`, where `n` is the total number of elements. concat :: forall a. List (List a) -> List a -concat = (_ >>= identity) +concat = join -- | Apply a function to each element in a list, and flatten the results -- | into a single, new list. @@ -429,13 +425,6 @@ mapMaybe f = go Nil catMaybes :: forall a. List (Maybe a) -> List a catMaybes = mapMaybe identity - --- | Apply a function to each element and its index in a list starting at 0. --- | --- | Deprecated. Use Data.FunctorWithIndex instead. -mapWithIndex :: forall a b. (Int -> a -> b) -> List a -> List b -mapWithIndex = FWI.mapWithIndex - -------------------------------------------------------------------------------- -- Sorting --------------------------------------------------------------------- -------------------------------------------------------------------------------- @@ -606,10 +595,6 @@ group = groupBy (==) groupAll :: forall a. Ord a => List a -> List (NEL.NonEmptyList a) groupAll = group <<< sort --- | Deprecated previous name of `groupAll`. -group' :: forall a. Warn (Text "'group\'' is deprecated, use groupAll instead") => Ord a => List a -> List (NEL.NonEmptyList a) -group' = groupAll - -- | Group equal, consecutive elements of a list into lists, using the specified -- | equivalence relation to determine equality. -- | @@ -626,17 +611,16 @@ groupBy _ Nil = Nil groupBy eq (x : xs) = case span (eq x) xs of { init: ys, rest: zs } -> NEL.NonEmptyList (x :| ys) : groupBy eq zs --- | Group equal elements of a list into lists, using the specified --- | equivalence relation to determine equality. --- | --- | For example, +-- | Sort, then group equal elements of a list into lists, using the provided comparison function. -- | -- | ```purescript --- | groupAllBy (\a b -> odd a && odd b) (1 : 3 : 2 : 4 : 3 : 3 : Nil) == --- | (NonEmptyList (NonEmpty 1 Nil)) : (NonEmptyList (NonEmpty 2 Nil)) : (NonEmptyList (NonEmpty 3 (3 : 3 : Nil))) : (NonEmptyList (NonEmpty 4 Nil)) : Nil +-- | groupAllBy (compare `on` (_ `div` 10)) (32 : 31 : 21 : 22 : 11 : 33 : Nil) == +-- | NonEmptyList (11 :| Nil) : NonEmptyList (21 :| 22 : Nil) : NonEmptyList (32 :| 31 : 33) : Nil -- | ``` -groupAllBy :: forall a. Ord a => (a -> a -> Boolean) -> List a -> List (NEL.NonEmptyList a) -groupAllBy p = groupBy p <<< sort +-- | +-- | Running time: `O(n log n)` +groupAllBy :: forall a. (a -> a -> Ordering) -> List a -> List (NEL.NonEmptyList a) +groupAllBy p = groupBy (\x y -> p x y == EQ) <<< sortBy p -- | Returns a lists of elements which do and do not satisfy a predicate. -- | diff --git a/src/Data/List/Lazy/NonEmpty.purs b/src/Data/List/Lazy/NonEmpty.purs index d455b1e..d5d207d 100644 --- a/src/Data/List/Lazy/NonEmpty.purs +++ b/src/Data/List/Lazy/NonEmpty.purs @@ -66,8 +66,8 @@ tail (NonEmptyList nel) = case force nel of _ :| xs -> xs init :: NonEmptyList ~> L.List init (NonEmptyList nel) = - case force nel - of x :| xs -> + case force nel of + x :| xs -> maybe L.nil (x : _) (L.init xs) cons :: forall a. a -> NonEmptyList a -> NonEmptyList a diff --git a/src/Data/List/Lazy/Types.purs b/src/Data/List/Lazy/Types.purs index f313a79..6a4163b 100644 --- a/src/Data/List/Lazy/Types.purs +++ b/src/Data/List/Lazy/Types.purs @@ -8,7 +8,6 @@ import Control.Comonad (class Comonad) import Control.Extend (class Extend) import Control.Lazy as Z import Control.MonadPlus (class MonadPlus) -import Control.MonadZero (class MonadZero) import Control.Plus (class Plus) import Data.Eq (class Eq1, eq1) import Data.Foldable (class Foldable, foldMap, foldl, foldr) @@ -191,8 +190,6 @@ instance plusList :: Plus List where instance alternativeList :: Alternative List -instance monadZeroList :: MonadZero List - instance monadPlusList :: MonadPlus List instance extendList :: Extend List where diff --git a/src/Data/List/NonEmpty.purs b/src/Data/List/NonEmpty.purs index 01c3db7..42fa49e 100644 --- a/src/Data/List/NonEmpty.purs +++ b/src/Data/List/NonEmpty.purs @@ -32,7 +32,6 @@ module Data.List.NonEmpty , mapMaybe , catMaybes , appendFoldable - , mapWithIndex , sort , sortBy , take @@ -42,7 +41,6 @@ module Data.List.NonEmpty , span , group , groupAll - , group' , groupBy , groupAllBy , partition @@ -65,7 +63,6 @@ module Data.List.NonEmpty import Prelude import Data.Foldable (class Foldable) -import Data.FunctorWithIndex (mapWithIndex) as FWI import Data.List ((:)) import Data.List as L import Data.List.Types (NonEmptyList(..)) @@ -82,8 +79,6 @@ import Data.Semigroup.Foldable (fold1, foldMap1, for1_, sequence1_, traverse1_) import Data.Semigroup.Traversable (sequence1, traverse1, traverse1Default) as Exports import Data.Traversable (scanl, scanr) as Exports -import Prim.TypeError (class Warn, Text) - -- | Internal function: any operation on a list that is guaranteed not to delete -- | all elements also applies to a NEL, this function is a helper for defining -- | those cases. @@ -235,12 +230,6 @@ appendFoldable :: forall t a. Foldable t => NonEmptyList a -> t a -> NonEmptyLis appendFoldable (NonEmptyList (x :| xs)) ys = NonEmptyList (x :| (xs <> L.fromFoldable ys)) --- | Apply a function to each element and its index in a list starting at 0. --- | --- | Deprecated. Use Data.FunctorWithIndex instead. -mapWithIndex :: forall a b. (Int -> a -> b) -> NonEmptyList a -> NonEmptyList b -mapWithIndex = FWI.mapWithIndex - sort :: forall a. Ord a => NonEmptyList a -> NonEmptyList a sort xs = sortBy compare xs @@ -268,13 +257,10 @@ group = wrappedOperation "group" L.group groupAll :: forall a. Ord a => NonEmptyList a -> NonEmptyList (NonEmptyList a) groupAll = wrappedOperation "groupAll" L.groupAll -group' :: forall a. Warn (Text "'group\'' is deprecated, use groupAll instead") => Ord a => NonEmptyList a -> NonEmptyList (NonEmptyList a) -group' = groupAll - groupBy :: forall a. (a -> a -> Boolean) -> NonEmptyList a -> NonEmptyList (NonEmptyList a) groupBy = wrappedOperation "groupBy" <<< L.groupBy -groupAllBy :: forall a. Ord a => (a -> a -> Boolean) -> NonEmptyList a -> NonEmptyList (NonEmptyList a) +groupAllBy :: forall a. (a -> a -> Ordering) -> NonEmptyList a -> NonEmptyList (NonEmptyList a) groupAllBy = wrappedOperation "groupAllBy" <<< L.groupAllBy partition :: forall a. (a -> Boolean) -> NonEmptyList a -> { yes :: L.List a, no :: L.List a } diff --git a/src/Data/List/Types.purs b/src/Data/List/Types.purs index e27bc56..a44df65 100644 --- a/src/Data/List/Types.purs +++ b/src/Data/List/Types.purs @@ -14,7 +14,6 @@ import Control.Apply (lift2) import Control.Comonad (class Comonad) import Control.Extend (class Extend) import Control.MonadPlus (class MonadPlus) -import Control.MonadZero (class MonadZero) import Control.Plus (class Plus) import Data.Eq (class Eq1, eq1) import Data.Foldable (class Foldable, foldl, foldr, intercalate) @@ -176,8 +175,6 @@ instance plusList :: Plus List where instance alternativeList :: Alternative List -instance monadZeroList :: MonadZero List - instance monadPlusList :: MonadPlus List instance extendList :: Extend List where diff --git a/test/Test/Data/List.purs b/test/Test/Data/List.purs index 5ac2db8..a96b6d7 100644 --- a/test/Test/Data/List.purs +++ b/test/Test/Data/List.purs @@ -3,10 +3,10 @@ module Test.Data.List (testList) where import Prelude import Data.Array as Array -import Data.Foldable (foldMap, foldl) +import Data.Foldable (class Foldable, foldMap, foldl) import Data.FoldableWithIndex (foldMapWithIndex, foldlWithIndex, foldrWithIndex) import Data.Function (on) -import Data.List (List(..), Pattern(..), alterAt, catMaybes, concat, concatMap, delete, deleteAt, deleteBy, drop, dropEnd, dropWhile, elemIndex, elemLastIndex, filter, filterM, findIndex, findLastIndex, foldM, fromFoldable, group, groupAll, groupAllBy, groupBy, head, init, insert, insertAt, insertBy, intersect, intersectBy, last, length, mapMaybe, mapWithIndex, modifyAt, nub, nubBy, nubByEq, nubEq, null, partition, range, reverse, singleton, snoc, sort, sortBy, span, stripPrefix, tail, take, takeEnd, takeWhile, transpose, uncons, union, unionBy, unsnoc, unzip, updateAt, zip, zipWith, zipWithA, (!!), (..), (:), (\\)) +import Data.List (List(..), Pattern(..), alterAt, catMaybes, concat, concatMap, delete, deleteAt, deleteBy, drop, dropEnd, dropWhile, elemIndex, elemLastIndex, filter, filterM, findIndex, findLastIndex, foldM, fromFoldable, group, groupAll, groupAllBy, groupBy, head, init, insert, insertAt, insertBy, intersect, intersectBy, last, length, mapMaybe, modifyAt, nub, nubBy, nubByEq, nubEq, null, partition, range, reverse, singleton, snoc, sort, sortBy, span, stripPrefix, tail, take, takeEnd, takeWhile, transpose, uncons, union, unionBy, unsnoc, unzip, updateAt, zip, zipWith, zipWithA, (!!), (..), (:), (\\)) import Data.List.NonEmpty as NEL import Data.Maybe (Maybe(..), isNothing, fromJust) import Data.Monoid.Additive (Additive(..)) @@ -23,7 +23,11 @@ import Test.Assert (assert) testList :: Effect Unit testList = do - let l = fromFoldable + let + l = fromFoldable + + nel :: forall f a. Foldable f => a -> f a -> NEL.NonEmptyList a + nel x xs = NEL.NonEmptyList $ x :| fromFoldable xs log "strip prefix" assert $ stripPrefix (Pattern (1:Nil)) (1:2:Nil) == Just (2:Nil) @@ -218,9 +222,6 @@ testList = do log "catMaybe should take an list of Maybe values and throw out Nothings" assert $ catMaybes (l [Nothing, Just 2, Nothing, Just 4]) == l [2, 4] - log "mapWithIndex should take a list of values and apply a function which also takes the index into account" - assert $ mapWithIndex (\x ix -> x + ix) (l [0, 1, 2, 3]) == l [0, 2, 4, 6] - log "sort should reorder a list into ascending order based on the result of compare" assert $ sort (l [1, 3, 2, 5, 6, 4]) == l [1, 2, 3, 4, 5, 6] @@ -275,8 +276,8 @@ testList = do log "groupBy should group consecutive equal elements into lists based on an equivalence relation" assert $ groupBy (\x y -> odd x && odd y) (l [1, 1, 2, 2, 3, 3]) == l [NEL.NonEmptyList (1 :| l [1]), NEL.singleton 2, NEL.singleton 2, NEL.NonEmptyList (3 :| l [3])] - log "groupAllBy should group equal elements into lists based on an equivalence relation" - assert $ groupAllBy (\x y -> odd x && odd y) (l [1, 3, 2, 4, 3, 3]) == l [NEL.singleton 1, NEL.singleton 2, NEL.NonEmptyList (3 :| l [3, 3]), NEL.singleton 4] + log "groupAllBy should sort then group equal elements into lists based on a comparison function" + assert $ groupAllBy (compare `on` (_ `div` 10)) (l [32, 31, 21, 22, 11, 33]) == l [nel 11 [], nel 21 [22], nel 32 [31, 33]] log "partition should separate a list into a tuple of lists that do and do not satisfy a predicate" let partitioned = partition (_ > 2) (l [1, 5, 3, 2, 4]) diff --git a/test/Test/Data/List/NonEmpty.purs b/test/Test/Data/List/NonEmpty.purs index b12380a..6ad71c1 100644 --- a/test/Test/Data/List/NonEmpty.purs +++ b/test/Test/Data/List/NonEmpty.purs @@ -21,9 +21,9 @@ import Test.Assert (assert) testNonEmptyList :: Effect Unit testNonEmptyList = do let - nel :: ∀ f a. Foldable f => a -> f a -> NEL.NonEmptyList a + nel :: forall f a. Foldable f => a -> f a -> NEL.NonEmptyList a nel x xs = NEL.NonEmptyList $ x :| L.fromFoldable xs - l :: ∀ f a. Foldable f => f a -> L.List a + l :: forall f a. Foldable f => f a -> L.List a l = L.fromFoldable log "singleton should construct a non-empty list with a single value" @@ -137,9 +137,6 @@ testNonEmptyList = do log "catMaybe should take an list of Maybe values and throw out Nothings" assert $ NEL.catMaybes (nel Nothing [Just 2, Nothing, Just 4]) == l [2, 4] - log "mapWithIndex should take a list of values and apply a function which also takes the index into account" - assert $ NEL.mapWithIndex (\x ix -> x + ix) (nel 0 [1, 2, 4]) == nel 0 [2, 4, 7] - log "sort should reorder a non-empty list into ascending order based on the result of compare" assert $ NEL.sort (nel 1 [3, 2, 5, 6, 4]) == nel 1 [2, 3, 4, 5, 6] @@ -176,8 +173,8 @@ testNonEmptyList = do log "groupBy should group consecutive equal elements into lists based on an equivalence relation" assert $ NEL.groupBy (\x y -> odd x && odd y) (nel 1 [1, 2, 2, 3, 3]) == nel (nel 1 [1]) [nel 2 [], nel 2 [], nel 3 [3]] - log "groupAllBy should group equal elements into lists based on an equivalence relation" - assert $ NEL.groupAllBy (\x y -> odd x && odd y) (nel 1 [3, 2, 4, 3, 3]) == nel (nel 1 []) [nel 2 [], nel 3 [3, 3], nel 4 []] + log "groupAllBy should sort then group equal elements into lists based on a comparison function" + assert $ NEL.groupAllBy (compare `on` (_ `div` 10)) (nel 32 [31, 21, 22, 11, 33]) == nel (nel 11 []) [nel 21 [22], nel 32 [31, 33]] log "partition should separate a list into a tuple of lists that do and do not satisfy a predicate" let partitioned = NEL.partition (_ > 2) (nel 1 [5, 3, 2, 4]) @@ -284,10 +281,6 @@ testNonEmptyList = do log "unfoldr1 should maintain order" assert $ (nel 1 [2, 3, 4, 5]) == unfoldr1 step1 1 -step :: Int -> Maybe (Tuple Int Int) -step 6 = Nothing -step n = Just (Tuple n (n + 1)) - step1 :: Int -> Tuple Int (Maybe Int) step1 n = Tuple n (if n >= 5 then Nothing else Just (n + 1))