diff --git a/src/Data/List/Lazy/Types.purs b/src/Data/List/Lazy/Types.purs index 1e1976a..dbae201 100644 --- a/src/Data/List/Lazy/Types.purs +++ b/src/Data/List/Lazy/Types.purs @@ -12,16 +12,16 @@ import Control.MonadZero (class MonadZero) import Control.Plus (class Plus) import Data.Eq (class Eq1, eq1) import Data.Foldable (class Foldable, foldMap, foldl, foldr) -import Data.FoldableWithIndex (class FoldableWithIndex, foldlWithIndex, foldrWithIndex) -import Data.FunctorWithIndex (class FunctorWithIndex) +import Data.FoldableWithIndex (class FoldableWithIndex, foldlWithIndex, foldrWithIndex, foldMapWithIndex) +import Data.FunctorWithIndex (class FunctorWithIndex, mapWithIndex) import Data.Lazy (Lazy, defer, force) -import Data.Maybe (Maybe(..)) +import Data.Maybe (Maybe(..), maybe) import Data.Newtype (class Newtype, unwrap) import Data.NonEmpty (NonEmpty, (:|)) import Data.NonEmpty as NE import Data.Ord (class Ord1, compare1) import Data.Traversable (class Traversable, traverse, sequence) -import Data.TraversableWithIndex (class TraversableWithIndex) +import Data.TraversableWithIndex (class TraversableWithIndex, traverseWithIndex) import Data.Tuple (Tuple(..), snd) import Data.Unfoldable (class Unfoldable) import Data.Unfoldable1 (class Unfoldable1) @@ -269,3 +269,15 @@ instance traversableNonEmptyList :: Traversable NonEmptyList where map (\xxs -> NonEmptyList $ defer \_ -> xxs) $ traverse f (force nel) sequence (NonEmptyList nel) = map (\xxs -> NonEmptyList $ defer \_ -> xxs) $ sequence (force nel) + +instance functorWithIndexNonEmptyList :: FunctorWithIndex Int NonEmptyList where + mapWithIndex f (NonEmptyList ne) = NonEmptyList $ defer \_ -> mapWithIndex (f <<< maybe 0 (add 1)) $ force ne + +instance foldableWithIndexNonEmptyList :: FoldableWithIndex Int NonEmptyList where + foldMapWithIndex f (NonEmptyList ne) = foldMapWithIndex (f <<< maybe 0 (add 1)) $ force ne + foldlWithIndex f b (NonEmptyList ne) = foldlWithIndex (f <<< maybe 0 (add 1)) b $ force ne + foldrWithIndex f b (NonEmptyList ne) = foldrWithIndex (f <<< maybe 0 (add 1)) b $ force ne + +instance traversableWithIndexNonEmptyList :: TraversableWithIndex Int NonEmptyList where + traverseWithIndex f (NonEmptyList ne) = + map (\xxs -> NonEmptyList $ defer \_ -> xxs) $ traverseWithIndex (f <<< maybe 0 (add 1)) $ force ne diff --git a/src/Data/List/NonEmpty.purs b/src/Data/List/NonEmpty.purs index c114bb7..f727ee2 100644 --- a/src/Data/List/NonEmpty.purs +++ b/src/Data/List/NonEmpty.purs @@ -59,6 +59,7 @@ 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(..)) @@ -219,8 +220,11 @@ 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 = wrappedOperation "mapWithIndex" <<< L.mapWithIndex +mapWithIndex = FWI.mapWithIndex sort :: forall a. Ord a => NonEmptyList a -> NonEmptyList a sort xs = sortBy compare xs diff --git a/src/Data/List/Types.purs b/src/Data/List/Types.purs index fcebde8..6de2f5f 100644 --- a/src/Data/List/Types.purs +++ b/src/Data/List/Types.purs @@ -12,9 +12,9 @@ import Control.MonadZero (class MonadZero) import Control.Plus (class Plus) import Data.Eq (class Eq1, eq1) import Data.Foldable (class Foldable, foldl, foldr, intercalate) -import Data.FoldableWithIndex (class FoldableWithIndex, foldlWithIndex, foldrWithIndex) -import Data.FunctorWithIndex (class FunctorWithIndex) -import Data.Maybe (Maybe(..)) +import Data.FoldableWithIndex (class FoldableWithIndex, foldlWithIndex, foldrWithIndex, foldMapWithIndex) +import Data.FunctorWithIndex (class FunctorWithIndex, mapWithIndex) +import Data.Maybe (Maybe(..), maybe) import Data.Newtype (class Newtype) import Data.NonEmpty (NonEmpty, (:|)) import Data.NonEmpty as NE @@ -22,7 +22,7 @@ import Data.Ord (class Ord1, compare1) import Data.Semigroup.Foldable (class Foldable1) import Data.Semigroup.Traversable (class Traversable1, traverse1) import Data.Traversable (class Traversable, traverse) -import Data.TraversableWithIndex (class TraversableWithIndex) +import Data.TraversableWithIndex (class TraversableWithIndex, traverseWithIndex) import Data.Tuple (Tuple(..), snd) import Data.Unfoldable (class Unfoldable) import Data.Unfoldable1 (class Unfoldable1) @@ -213,6 +213,17 @@ derive newtype instance traversableNonEmptyList :: Traversable NonEmptyList derive newtype instance foldable1NonEmptyList :: Foldable1 NonEmptyList +instance functorWithIndexNonEmptyList :: FunctorWithIndex Int NonEmptyList where + mapWithIndex fn (NonEmptyList ne) = NonEmptyList $ mapWithIndex (fn <<< maybe 0 (add 1)) ne + +instance foldableWithIndexNonEmptyList :: FoldableWithIndex Int NonEmptyList where + foldMapWithIndex f (NonEmptyList ne) = foldMapWithIndex (f <<< maybe 0 (add 1)) ne + foldlWithIndex f b (NonEmptyList ne) = foldlWithIndex (f <<< maybe 0 (add 1)) b ne + foldrWithIndex f b (NonEmptyList ne) = foldrWithIndex (f <<< maybe 0 (add 1)) b ne + +instance traversableWithIndexNonEmptyList :: TraversableWithIndex Int NonEmptyList where + traverseWithIndex f (NonEmptyList ne) = NonEmptyList <$> traverseWithIndex (f <<< maybe 0 (add 1)) ne + instance traversable1NonEmptyList :: Traversable1 NonEmptyList where traverse1 f (NonEmptyList (a :| as)) = foldl (\acc -> lift2 (flip nelCons) acc <<< f) (pure <$> f a) as diff --git a/test/Test/Data/List.purs b/test/Test/Data/List.purs index 44966b3..f725ed5 100644 --- a/test/Test/Data/List.purs +++ b/test/Test/Data/List.purs @@ -217,7 +217,7 @@ testList = do 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) (fromFoldable [0, 1, 2, 3]) == fromFoldable [0, 2, 4, 6] + 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] diff --git a/test/Test/Data/List/Lazy.purs b/test/Test/Data/List/Lazy.purs index a108215..d538ca1 100644 --- a/test/Test/Data/List/Lazy.purs +++ b/test/Test/Data/List/Lazy.purs @@ -52,31 +52,40 @@ testListLazy = do log "foldlWithIndex should be correct" assert $ foldlWithIndex (\i b _ -> i + b) 0 (range 0 10000) == 50005000 + assert $ map (foldlWithIndex (\i b _ -> i + b) 0) (NEL.fromFoldable (range 0 10000)) == Just 50005000 log "foldlWithIndex should be stack-safe" void $ pure $ foldlWithIndex (\i b _ -> i + b) 0 $ range 0 100000 + void $ pure $ map (foldlWithIndex (\i b _ -> i + b) 0) $ NEL.fromFoldable $ range 0 100000 log "foldrWithIndex should be correct" assert $ foldrWithIndex (\i _ b -> i + b) 0 (range 0 10000) == 50005000 + assert $ map (foldrWithIndex (\i _ b -> i + b) 0) (NEL.fromFoldable (range 0 10000)) == Just 50005000 log "foldrWithIndex should be stack-safe" void $ pure $ foldrWithIndex (\i _ b -> i + b) 0 $ range 0 100000 + void $ pure $ map (foldrWithIndex (\i _ b -> i + b) 0) $ NEL.fromFoldable $ range 0 100000 log "foldMapWithIndex should be stack-safe" void $ pure $ foldMapWithIndex (\i _ -> Additive i) $ range 1 100000 + void $ pure $ map (foldMapWithIndex (\i _ -> Additive i)) $ NEL.fromFoldable $ range 1 100000 log "foldMapWithIndex should be left-to-right" assert $ foldMapWithIndex (\i _ -> show i) (fromFoldable [0, 0, 0]) == "012" + assert $ map (foldMapWithIndex (\i _ -> show i)) (NEL.fromFoldable [0, 0, 0]) == Just "012" log "traverse should be stack-safe" assert $ ((traverse Just longList) >>= last) == last longList log "traverseWithIndex should be stack-safe" assert $ traverseWithIndex (const Just) longList == Just longList + assert $ traverseWithIndex (const Just) (NEL.fromFoldable longList) == Just (NEL.fromFoldable longList) log "traverseWithIndex should be correct" assert $ traverseWithIndex (\i a -> Just $ i + a) (fromFoldable [2, 2, 2]) == Just (fromFoldable [2, 3, 4]) + assert $ map (traverseWithIndex (\i a -> Just $ i + a)) (NEL.fromFoldable [2, 2, 2]) + == Just (NEL.fromFoldable [2, 3, 4]) log "bind should be stack-safe" void $ pure $ last $ longList >>= pure @@ -257,6 +266,7 @@ testListLazy = do 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) (fromFoldable [0, 1, 2, 3]) == fromFoldable [0, 2, 4, 6] + assert $ map (mapWithIndex (\x ix -> x + ix)) (NEL.fromFoldable [0, 1, 2, 3]) == NEL.fromFoldable [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] diff --git a/test/Test/Data/List/NonEmpty.purs b/test/Test/Data/List/NonEmpty.purs index a82b9c0..67ab102 100644 --- a/test/Test/Data/List/NonEmpty.purs +++ b/test/Test/Data/List/NonEmpty.purs @@ -5,6 +5,8 @@ import Prelude import Effect (Effect) import Effect.Console (log) import Data.Foldable (class Foldable, foldM, foldMap, foldl, length) +import Data.FoldableWithIndex (foldlWithIndex, foldrWithIndex, foldMapWithIndex) +import Data.TraversableWithIndex (traverseWithIndex) import Data.List as L import Data.List.NonEmpty as NEL import Data.Maybe (Maybe(..)) @@ -238,6 +240,31 @@ testNonEmptyList = do log "append should be stack-safe" void $ pure $ xs <> xs + log "foldlWithIndex should be correct" + assert $ (foldlWithIndex (\i b _ -> i + b) 0 <$> (NEL.fromFoldable (L.range 0 10000))) == Just 50005000 + + log "foldlWithIndex should be stack-safe" + void $ pure $ map (foldlWithIndex (\i b _ -> i + b) 0) $ NEL.fromFoldable $ L.range 0 100000 + + log "foldrWithIndex should be correct" + assert $ (foldrWithIndex (\i _ b -> i + b) 0 <$> (NEL.fromFoldable (L.range 0 10000))) == Just 50005000 + + log "foldrWithIndex should be stack-safe" + void $ pure $ map (foldrWithIndex (\i b _ -> i + b) 0) $ NEL.fromFoldable $ L.range 0 100000 + + log "foldMapWithIndex should be stack-safe" + void $ pure $ map (foldMapWithIndex (\i _ -> Additive i)) $ NEL.fromFoldable $ L.range 1 100000 + + log "foldMapWithIndex should be left-to-right" + assert $ map (foldMapWithIndex (\i _ -> show i)) (NEL.fromFoldable [0, 0, 0]) == Just "012" + + log "traverseWithIndex should be stack-safe" + assert $ map (traverseWithIndex (const Just)) (NEL.fromFoldable xs) == Just (NEL.fromFoldable xs) + + log "traverseWithIndex should be correct" + assert $ map (traverseWithIndex (\i a -> Just $ i + a)) (NEL.fromFoldable [2, 2, 2]) + == Just (NEL.fromFoldable [2, 3, 4]) + odd :: Int -> Boolean odd n = n `mod` 2 /= zero