Skip to content

Commit

Permalink
Merge pull request #151 from cryogenian/with-index
Browse files Browse the repository at this point in the history
added FunctorWithIndex, FoldableWithIndex, TraversableWithIndex insta…
  • Loading branch information
garyb committed Aug 19, 2018
2 parents 61e9c15 + 8fb5017 commit ad31f0a
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 10 deletions.
20 changes: 16 additions & 4 deletions src/Data/List/Lazy/Types.purs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
6 changes: 5 additions & 1 deletion src/Data/List/NonEmpty.purs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..))
Expand Down Expand Up @@ -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
Expand Down
19 changes: 15 additions & 4 deletions src/Data/List/Types.purs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ 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
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)
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion test/Test/Data/List.purs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
10 changes: 10 additions & 0 deletions test/Test/Data/List/Lazy.purs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]
Expand Down
27 changes: 27 additions & 0 deletions test/Test/Data/List/NonEmpty.purs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..))
Expand Down Expand Up @@ -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

Expand Down

0 comments on commit ad31f0a

Please sign in to comment.