Skip to content

Commit bca60d4

Browse files
committed
Add filterA, a faster version of filterM
Change filterM to just be filterA in order to have this be a non-breaking change. This removes another use of uncons, refs #71
1 parent 54e5240 commit bca60d4

File tree

3 files changed

+21
-15
lines changed

3 files changed

+21
-15
lines changed

bower.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
},
2727
"devDependencies": {
2828
"purescript-assert": "^2.0.0",
29-
"purescript-console": "^2.0.0"
29+
"purescript-console": "^2.0.0",
30+
"purescript-const": "^2.0.0"
3031
}
3132
}

src/Data/Array.purs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ module Data.Array
6767
, concatMap
6868
, filter
6969
, partition
70+
, filterA
7071
, filterM
7172
, mapMaybe
7273
, catMaybes
@@ -110,21 +111,18 @@ module Data.Array
110111
) where
111112

112113
import Prelude
113-
114114
import Control.Alt ((<|>))
115115
import Control.Alternative (class Alternative)
116116
import Control.Lazy (class Lazy, defer)
117117
import Control.Monad.Rec.Class (class MonadRec, Step(..), tailRecM2)
118-
119118
import Data.Foldable (class Foldable, foldl, foldr)
120119
import Data.Foldable (foldl, foldr, foldMap, fold, intercalate, elem, notElem, find, findMap, any, all) as Exports
121120
import Data.Maybe (Maybe(..), maybe, isJust, fromJust)
122121
import Data.NonEmpty (NonEmpty, (:|))
123122
import Data.Traversable (scanl, scanr) as Exports
124-
import Data.Traversable (sequence)
123+
import Data.Traversable (sequence, traverse)
125124
import Data.Tuple (Tuple(..))
126125
import Data.Unfoldable (class Unfoldable, unfoldr)
127-
128126
import Partial.Unsafe (unsafePartial)
129127

130128
-- | Convert an `Array` into an `Unfoldable` structure.
@@ -417,17 +415,20 @@ foreign import partition
417415
-> Array a
418416
-> { yes :: Array a, no :: Array a }
419417

420-
-- | Filter where the predicate returns a monadic `Boolean`.
418+
-- | Filter where the predicate returns a `Boolean` in some `Applicative`.
421419
-- |
422420
-- | ```purescript
423-
-- | powerSet :: forall a. [a] -> [[a]]
424-
-- | powerSet = filterM (const [true, false])
421+
-- | powerSet :: forall a. Array a -> Array (Array a)
422+
-- | powerSet = filterA (const [true, false])
425423
-- | ```
424+
filterA :: forall a f. Applicative f => (a -> f Boolean) -> Array a -> f (Array a)
425+
filterA p =
426+
traverse (\x -> Tuple x <$> p x)
427+
>>> map (mapMaybe (\(Tuple x b) -> if b then Just x else Nothing))
428+
429+
-- | Deprecated alias for `filterA`.
426430
filterM :: forall a m. Monad m => (a -> m Boolean) -> Array a -> m (Array a)
427-
filterM p = uncons' (\_ -> pure []) \x xs -> do
428-
b <- p x
429-
xs' <- filterM p xs
430-
pure if b then x : xs' else xs'
431+
filterM = filterA
431432

432433
-- | Apply a function to each element in an array, keeping only the results
433434
-- | which contain a value, creating a new array.

test/Test/Data/Array.purs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Prelude
55
import Control.Monad.Eff (Eff)
66
import Control.Monad.Eff.Console (log, CONSOLE)
77

8+
import Data.Const (Const(..))
89
import Data.Array as A
910
import Data.Array ((:), (\\), (!!))
1011
import Data.Foldable (for_, foldMapDefaultR, class Foldable, all, traverse_)
@@ -205,9 +206,12 @@ testArray = do
205206
log "filter should remove items that don't match a predicate"
206207
assert $ A.filter odd (A.range 0 10) == [1, 3, 5, 7, 9]
207208

208-
log "filterM should remove items that don't match a predicate while using a monadic behaviour"
209-
assert $ A.filterM (Just <<< odd) (A.range 0 10) == Just [1, 3, 5, 7, 9]
210-
assert $ A.filterM (const Nothing) (A.range 0 10) == Nothing
209+
log "filterA should remove items that don't match a predicate while using an applicative behaviour"
210+
assert $ A.filterA (Just <<< odd) (A.range 0 10) == Just [1, 3, 5, 7, 9]
211+
assert $ A.filterA (const Nothing) (A.range 0 10) == Nothing
212+
213+
log "filterA should apply effects in the right order"
214+
assert $ A.filterA (Const <<< show) (A.range 1 5) == Const "12345"
211215

212216
log "mapMaybe should transform every item in an array, throwing out Nothing values"
213217
assert $ A.mapMaybe (\x -> if x /= 0 then Just x else Nothing) [0, 1, 0, 0, 2, 3] == [1, 2, 3]

0 commit comments

Comments
 (0)