Skip to content

Commit 6ea6d51

Browse files
authored
Add mapMaybe to sets and Seq (#1159)
1 parent c1c5dee commit 6ea6d51

File tree

11 files changed

+81
-2
lines changed

11 files changed

+81
-2
lines changed

containers-tests/tests/intmap-properties.hs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ main = defaultMain $ testGroup "intmap-properties"
189189
, testProperty "filterKeys" prop_filterKeys
190190
, testProperty "filterWithKey" prop_filterWithKey
191191
, testProperty "partition" prop_partition
192+
, testProperty "mapMaybe" prop_mapMaybe
192193
, testProperty "takeWhileAntitone" prop_takeWhileAntitone
193194
, testProperty "dropWhileAntitone" prop_dropWhileAntitone
194195
, testProperty "spanAntitone" prop_spanAntitone
@@ -1552,6 +1553,13 @@ prop_filterWithKey fun m =
15521553
where
15531554
m' = filterWithKey (applyFun2 fun) m
15541555

1556+
prop_mapMaybe :: Fun Int (Maybe Bool) -> IMap -> Property
1557+
prop_mapMaybe f m =
1558+
valid m' .&&.
1559+
toList m' === Maybe.mapMaybe (\(k,x) -> (,) k <$> applyFun f x) (toList m)
1560+
where
1561+
m' = mapMaybe (applyFun f) m
1562+
15551563
prop_partition :: Fun Int Bool -> [(Int, Int)] -> Property
15561564
prop_partition p ys = length ys > 0 ==>
15571565
let xs = List.nubBy ((==) `on` fst) ys

containers-tests/tests/intset-properties.hs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Data.IntSet
66
import Data.List (nub,sort)
77
import qualified Data.List as List
88
import Data.Maybe (listToMaybe)
9+
import qualified Data.Maybe as Maybe
910
import Data.Monoid (mempty)
1011
import Data.List.NonEmpty (NonEmpty(..))
1112
import qualified Data.List.NonEmpty as NE
@@ -79,6 +80,7 @@ main = defaultMain $ testGroup "intset-properties"
7980
, testProperty "prop_splitRoot" prop_splitRoot
8081
, testProperty "prop_partition" prop_partition
8182
, testProperty "prop_filter" prop_filter
83+
, testProperty "prop_mapMaybe" prop_mapMaybe
8284
, testProperty "takeWhileAntitone" prop_takeWhileAntitone
8385
, testProperty "dropWhileAntitone" prop_dropWhileAntitone
8486
, testProperty "spanAntitone" prop_spanAntitone
@@ -457,6 +459,12 @@ prop_filter s i =
457459
valid evens .&&.
458460
parts === (odds, evens)
459461

462+
prop_mapMaybe :: Fun Int (Maybe Int) -> IntSet -> Property
463+
prop_mapMaybe f s =
464+
let mapped = mapMaybe (applyFun f) s
465+
in valid mapped .&&.
466+
mapped === fromList (Maybe.mapMaybe (applyFun f) $ toList s)
467+
460468
prop_takeWhileAntitone :: Int -> [Int] -> Property
461469
prop_takeWhileAntitone x ys =
462470
let l = takeWhileAntitone (<x) (fromList ys)

containers-tests/tests/seq-properties.hs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ import Data.Array (listArray)
2424
import Data.Coerce (coerce)
2525
import Data.Foldable (Foldable(foldl, foldl1, foldr, foldr1, foldMap, fold), toList, all, sum, foldl', foldr')
2626
import Data.Functor ((<$>), (<$))
27-
import Data.Maybe
27+
import Data.Maybe (listToMaybe)
28+
import qualified Data.Maybe as Maybe
2829
import Data.Function (on)
2930
import Data.Monoid (Monoid(..), All(..), Endo(..), Dual(..))
3031
import Data.Semigroup (stimes, stimesMonoid)
@@ -100,6 +101,7 @@ main = defaultMain $ testGroup "seq-properties"
100101
, testProperty "breakr" prop_breakr
101102
, testProperty "partition" prop_partition
102103
, testProperty "filter" prop_filter
104+
, testProperty "mapMaybe" prop_mapMaybe
103105
, testProperty "sort" prop_sort
104106
, testProperty "sortStable" prop_sortStable
105107
, testProperty "sortBy" prop_sortBy
@@ -553,6 +555,10 @@ prop_filter (Positive n) xs =
553555
toList' (filter p xs) ~= Prelude.filter p (toList xs)
554556
where p x = x `mod` n == 0
555557

558+
prop_mapMaybe :: Fun Int (Maybe Int) -> Seq Int -> Bool
559+
prop_mapMaybe f xs =
560+
toList' (mapMaybe (applyFun f) xs) ~= Maybe.mapMaybe (applyFun f) (toList xs)
561+
556562
-- * Sorting
557563

558564
prop_sort :: Seq OrdA -> Bool

containers-tests/tests/set-properties.hs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
import qualified Data.IntSet as IntSet
33
import Data.List (nub, sort, sortBy)
44
import qualified Data.List as List
5-
import Data.Maybe
5+
import Data.Maybe (isJust, fromJust)
6+
import qualified Data.Maybe as Maybe
67
import Data.Set
78
import Data.Set.Internal (link, merge)
89
import Prelude hiding (lookup, null, map, filter, foldr, foldl, foldl', all, take, drop, splitAt)
@@ -98,6 +99,7 @@ main = defaultMain $ testGroup "set-properties"
9899
, testProperty "prop_splitRoot" prop_splitRoot
99100
, testProperty "prop_partition" prop_partition
100101
, testProperty "prop_filter" prop_filter
102+
, testProperty "prop_mapMaybe" prop_mapMaybe
101103
, testProperty "takeWhileAntitone" prop_takeWhileAntitone
102104
, testProperty "dropWhileAntitone" prop_dropWhileAntitone
103105
, testProperty "spanAntitone" prop_spanAntitone
@@ -618,6 +620,12 @@ prop_partition s i = case partition odd s of
618620
prop_filter :: Set Int -> Int -> Bool
619621
prop_filter s i = partition odd s == (filter odd s, filter even s)
620622

623+
prop_mapMaybe :: Fun Int (Maybe Int) -> Set Int -> Property
624+
prop_mapMaybe f s =
625+
let mapped = mapMaybe (applyFun f) s
626+
in valid mapped .&&.
627+
mapped === fromList (Maybe.mapMaybe (applyFun f) $ toList s)
628+
621629
prop_take :: Int -> Set Int -> Property
622630
prop_take n xs = valid taken .&&.
623631
taken === fromDistinctAscList (List.take n (toList xs))

containers/changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
* Add `compareSize` for `IntSet` and `IntMap`. (Soumik Sarkar)
88
([#1135](https://github.com/haskell/containers/pull/1135))
99

10+
* Add `mapMaybe` for `Seq`, `Set` and `IntSet`. (Phil Hazelden)
11+
([#1159](https://github.com/haskell/containers/pull/1159)
12+
1013
### Performance improvements
1114

1215
* Improved performance for `Data.IntMap.restrictKeys` and

containers/src/Data/IntSet.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ module Data.IntSet (
145145
, dropWhileAntitone
146146
, spanAntitone
147147

148+
, mapMaybe
149+
148150
, split
149151
, splitMember
150152
, splitRoot

containers/src/Data/IntSet/Internal.hs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ module Data.IntSet.Internal (
134134
, dropWhileAntitone
135135
, spanAntitone
136136

137+
, mapMaybe
138+
137139
, split
138140
, splitMember
139141
, splitRoot
@@ -880,6 +882,18 @@ filter predicate t
880882
| otherwise = bm
881883
{-# INLINE bitPred #-}
882884

885+
-- | \(O(n \min(n,W))\). Map elements and collect the 'Just' results.
886+
--
887+
-- If the function is monotonically non-decreasing or monotonically
888+
-- non-increasing, 'mapMaybe' takes \(O(n)\) time.
889+
--
890+
-- @since FIXME
891+
mapMaybe :: (Key -> Maybe Key) -> IntSet -> IntSet
892+
mapMaybe f t = finishB (foldl' go emptyB t)
893+
where go b x = case f x of
894+
Nothing -> b
895+
Just x' -> insertB x' b
896+
883897
-- | \(O(n)\). partition the set according to some predicate.
884898
partition :: (Key -> Bool) -> IntSet -> (IntSet,IntSet)
885899
partition predicate0 t0 = toPair $ go predicate0 t0

containers/src/Data/Sequence.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ module Data.Sequence (
192192
breakr, -- :: (a -> Bool) -> Seq a -> (Seq a, Seq a)
193193
partition, -- :: (a -> Bool) -> Seq a -> (Seq a, Seq a)
194194
filter, -- :: (a -> Bool) -> Seq a -> Seq a
195+
mapMaybe, -- :: (a -> Maybe b) -> Seq a -> Seq b
195196
-- * Sorting
196197
sort, -- :: Ord a => Seq a -> Seq a
197198
sortBy, -- :: (a -> a -> Ordering) -> Seq a -> Seq a

containers/src/Data/Sequence/Internal.hs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ module Data.Sequence.Internal (
128128
breakr, -- :: (a -> Bool) -> Seq a -> (Seq a, Seq a)
129129
partition, -- :: (a -> Bool) -> Seq a -> (Seq a, Seq a)
130130
filter, -- :: (a -> Bool) -> Seq a -> Seq a
131+
mapMaybe, -- :: (a -> Maybe b) -> Seq a -> Seq b
131132
-- * Indexing
132133
lookup, -- :: Int -> Seq a -> Maybe a
133134
(!?), -- :: Seq a -> Int -> Maybe a
@@ -4199,6 +4200,15 @@ partition p = toPair . foldl' part (empty :*: empty)
41994200
filter :: (a -> Bool) -> Seq a -> Seq a
42004201
filter p = foldl' (\ xs x -> if p x then xs `snoc'` x else xs) empty
42014202

4203+
-- | \( O(n) \). Map elements and collect the 'Just' results.
4204+
--
4205+
-- @since FIXME
4206+
mapMaybe :: (a -> Maybe b) -> Seq a -> Seq b
4207+
mapMaybe f = foldl' go empty
4208+
where go xs x = case f x of
4209+
Nothing -> xs
4210+
Just x' -> xs `snoc'` x'
4211+
42024212
-- Indexing sequences
42034213

42044214
-- | 'elemIndexL' finds the leftmost index of the specified element,

containers/src/Data/Set.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ module Data.Set (
137137
, takeWhileAntitone
138138
, dropWhileAntitone
139139
, spanAntitone
140+
, mapMaybe
140141
, partition
141142
, split
142143
, splitMember

0 commit comments

Comments
 (0)