packages feed

containers 0.6.2.1 → 0.6.3.1

raw patch · 20 files changed

+1184/−232 lines, 20 filesdep ~basePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: base

API changes (from Hackage documentation)

+ Data.IntMap.Internal: compose :: IntMap c -> IntMap Int -> IntMap c
+ Data.IntMap.Internal: linkWithMask :: Mask -> Prefix -> IntMap a -> IntMap a -> IntMap a
+ Data.IntMap.Lazy: compose :: IntMap c -> IntMap Int -> IntMap c
+ Data.IntMap.Strict: compose :: IntMap c -> IntMap Int -> IntMap c
+ Data.IntMap.Strict.Internal: compose :: IntMap c -> IntMap Int -> IntMap c
+ Data.IntSet: alterF :: Functor f => (Bool -> f Bool) -> Key -> IntSet -> f IntSet
+ Data.IntSet: mapMonotonic :: (Key -> Key) -> IntSet -> IntSet
+ Data.IntSet.Internal: alterF :: Functor f => (Bool -> f Bool) -> Key -> IntSet -> f IntSet
+ Data.IntSet.Internal: instance GHC.Classes.Eq Data.IntSet.Internal.Relation
+ Data.IntSet.Internal: instance GHC.Show.Show Data.IntSet.Internal.Relation
+ Data.IntSet.Internal: mapMonotonic :: (Key -> Key) -> IntSet -> IntSet
+ Data.Map.Internal: compose :: Ord b => Map b c -> Map a b -> Map a c
+ Data.Map.Internal: instance Data.Bifoldable.Bifoldable Data.Map.Internal.Map
+ Data.Map.Lazy: compose :: Ord b => Map b c -> Map a b -> Map a c
+ Data.Map.Strict: compose :: Ord b => Map b c -> Map a b -> Map a c
+ Data.Map.Strict.Internal: compose :: Ord b => Map b c -> Map a b -> Map a c
+ Data.Set: alterF :: (Ord a, Functor f) => (Bool -> f Bool) -> a -> Set a -> f (Set a)
+ Data.Set.Internal: alterF :: (Ord a, Functor f) => (Bool -> f Bool) -> a -> Set a -> f (Set a)
- Data.Graph: Node :: a -> Forest a -> Tree a
+ Data.Graph: Node :: a -> [Tree a] -> Tree a
- Data.IntMap.Internal: fromDistinctAscList :: forall a. [(Key, a)] -> IntMap a
+ Data.IntMap.Internal: fromDistinctAscList :: [(Key, a)] -> IntMap a
- Data.IntMap.Lazy: fromDistinctAscList :: forall a. [(Key, a)] -> IntMap a
+ Data.IntMap.Lazy: fromDistinctAscList :: [(Key, a)] -> IntMap a
- Data.Tree: Node :: a -> Forest a -> Tree a
+ Data.Tree: Node :: a -> [Tree a] -> Tree a
- Data.Tree: [subForest] :: Tree a -> Forest a
+ Data.Tree: [subForest] :: Tree a -> [Tree a]
- Data.Tree: drawForest :: Forest String -> String
+ Data.Tree: drawForest :: [Tree String] -> String
- Data.Tree: unfoldForest :: (b -> (a, [b])) -> [b] -> Forest a
+ Data.Tree: unfoldForest :: (b -> (a, [b])) -> [b] -> [Tree a]
- Data.Tree: unfoldForestM :: Monad m => (b -> m (a, [b])) -> [b] -> m (Forest a)
+ Data.Tree: unfoldForestM :: Monad m => (b -> m (a, [b])) -> [b] -> m [Tree a]
- Data.Tree: unfoldForestM_BF :: Monad m => (b -> m (a, [b])) -> [b] -> m (Forest a)
+ Data.Tree: unfoldForestM_BF :: Monad m => (b -> m (a, [b])) -> [b] -> m [Tree a]

Files

changelog.md view
@@ -1,5 +1,58 @@ # Changelog for [`containers` package](http://github.com/haskell/containers) +## 0.6.3.1++### Bug fixes++* Fix `traverse` and `traverseWithKey` for `IntMap`, which would+  previously produce invalid `IntMap`s when the input contained+  negative keys (Thanks, Felix Paulusma).++* Fix the traversal order of various functions for `Data.IntMap`:+  `traverseWithKey`, `traverseMaybeWithKey`, `filterWithKeyA`,+  `minimum`, `maximum`, `mapAccum`, `mapAccumWithKey`, `mapAccumL`,+  `mapAccumRWithKey`, `mergeA` (Thanks, Felix Paulusma, Simon Jakobi).++### Additions++* Add `compose` for `Map` and `IntMap` (Thanks, Alexandre Esteves).++* Add `alterF` for `Set` and `IntSet` (Thanks, Simon Jakobi).++* Add `Data.IntSet.mapMonotonic` (Thanks, Javran Cheng).++* Add `instance Bifoldable Map` (Thanks, Joseph C. Sible).++### Performance improvements++* Make `(<*)` for `Data.Sequence` incrementally asymptotically optimal.+  This finally completes the task, begun in December 2014, of making all+  the `Applicative` methods for sequences asymptotically optimal+  even when their results are consumed incrementally. Many thanks to+  Li-Yao Xia and Bertram Felgenhauer for helping to clean up and begin+  to document this rather tricky code.++* Speed up `fromList` and related functions in `Data.IntSet`, `Data.IntMap`+  and `Data.IntMap.Strict` (Thanks, Bertram Felgenhauer).++* Use `count{Leading,Trailing}Zeros` in `Data.IntSet` internals (Thanks, Alex+  Biehl).++### Other changes++* Reduce usage of the `Forest` type synonym in `Data.Tree` (Thanks, David+  Feuer).++* Address a Core lint warning for `foldToMaybeTree` (Thanks, Matthew Pickering).++* Improve documentation (Thanks to Daniel Wagner, Johannes Waldmann, Steve Mao,+  Gabriel Greif, Jean-Baptiste Mazon, Ziyang Liu, Matt Renaud, Li-Yao Xia).++* Improvements to the testsuite and benchmarks (Thanks, Bertram Felgenhauer,+  Simon Jakobi, Johannes Waldmann).++* Canonicalise `Seq`'s `Monoid` instance (Thanks, Fumiaki Kinoshita).+ ## 0.6.2.1  * Add `disjoint` for `Map` and `IntMap` (Thanks, Simon Jakobi).
containers.cabal view
@@ -1,5 +1,5 @@ name: containers-version: 0.6.2.1+version: 0.6.3.1 license: BSD3 license-file: LICENSE maintainer: libraries@haskell.org@@ -20,18 +20,19 @@     remains valid even if structures are shared.  build-type: Simple-cabal-version:  >=1.8+cabal-version:  >=1.10 extra-source-files:     include/containers.h     changelog.md -tested-with: GHC==8.6.4, GHC==8.4.4, GHC==8.2.2, GHC==8.0.2, GHC==7.10.3, GHC==7.8.4, GHC==7.6.3+tested-with: GHC==8.8.2, GHC==8.6.5, GHC==8.4.4, GHC==8.2.2, GHC==8.0.2, GHC==7.10.3, GHC==7.8.4, GHC==7.6.3  source-repository head     type:     git     location: http://github.com/haskell/containers.git  Library+    default-language: Haskell2010     build-depends: base >= 4.6 && < 5, array >= 0.4.0.0, deepseq >= 1.2 && < 1.5     hs-source-dirs: src     ghc-options: -O2 -Wall
src/Data/Containers/ListUtils.hs view
@@ -17,6 +17,8 @@ -- In the documentation, \(n\) is the number of elements in the list while -- \(d\) is the number of distinct elements in the list. \(W\) is the number -- of bits in an 'Int'.+--+-- @since 0.6.0.1 -----------------------------------------------------------------------------  module Data.Containers.ListUtils (@@ -53,6 +55,8 @@ -- pathological cases. For example, to nub a list of characters, use -- -- @ nubIntOn fromEnum xs @+--+-- @since 0.6.0.1 nubOrd :: Ord a => [a] -> [a] nubOrd = nubOrdOn id {-# INLINE nubOrd #-}@@ -65,6 +69,8 @@ -- -- @nubOrdOn@ is strict in the values of the function applied to the -- elements of the list.+--+-- @since 0.6.0.1 nubOrdOn :: Ord b => (a -> b) -> [a] -> [a] -- For some reason we need to write an explicit lambda here to allow this -- to inline when only applied to a function.@@ -129,6 +135,8 @@ -- ==== Strictness -- -- @nubInt@ is strict in the elements of the list.+--+-- @since 0.6.0.1 nubInt :: [Int] -> [Int] nubInt = nubIntOn id {-# INLINE nubInt #-}@@ -142,6 +150,8 @@ -- -- @nubIntOn@ is strict in the values of the function applied to the -- elements of the list.+--+-- @since 0.6.0.1 nubIntOn :: (a -> Int) -> [a] -> [a] -- For some reason we need to write an explicit lambda here to allow this -- to inline when only applied to a function.
src/Data/Graph.hs view
@@ -383,7 +383,7 @@ -- type @key@ labeled by values of type @node@ and produces a @Graph@-based -- representation of that list. The @Graph@ result represents the /shape/ of the -- graph, and the functions describe a) how to retrieve the label and adjacent--- vertices of a given vertex, and b) how to retrive a vertex given a key.+-- vertices of a given vertex, and b) how to retrieve a vertex given a key. -- -- @(graph, nodeFromVertex, vertexFromKey) = graphFromEdges edgeList@ --
src/Data/IntMap/Internal.hs view
@@ -131,6 +131,9 @@     , intersectionWith     , intersectionWithKey +    -- ** Compose+    , compose+     -- ** General combining function     , SimpleWhenMissing     , SimpleWhenMatched@@ -266,6 +269,7 @@     , natFromInt     , intFromNat     , link+    , linkWithMask     , bin     , binCheckLeft     , binCheckRight@@ -478,7 +482,9 @@   maximum = start     where start Nil = error "Data.Foldable.maximum (for Data.IntMap): empty map"           start (Tip _ y) = y-          start (Bin _ _ l r) = go (start l) r+          start (Bin _ m l r)+            | m < 0     = go (start r) l+            | otherwise = go (start l) r            go !m Nil = m           go m (Tip _ y) = max m y@@ -487,7 +493,9 @@   minimum = start     where start Nil = error "Data.Foldable.minimum (for Data.IntMap): empty map"           start (Tip _ y) = y-          start (Bin _ _ l r) = go (start l) r+          start (Bin _ m l r)+            | m < 0     = go (start r) l+            | otherwise = go (start l) r            go !m Nil = m           go m (Tip _ y) = min m y@@ -761,6 +769,27 @@               | otherwise        = disjoint t1 r2  {--------------------------------------------------------------------+  Compose+--------------------------------------------------------------------}+-- | Relate the keys of one map to the values of+-- the other, by using the values of the former as keys for lookups+-- in the latter.+--+-- Complexity: \( O(n * \min(m,W)) \), where \(m\) is the size of the first argument+--+-- > compose (fromList [('a', "A"), ('b', "B")]) (fromList [(1,'a'),(2,'b'),(3,'z')]) = fromList [(1,"A"),(2,"B")]+--+-- @+-- ('compose' bc ab '!?') = (bc '!?') <=< (ab '!?')+-- @+--+-- @since 0.6.3.1+compose :: IntMap c -> IntMap Int -> IntMap c+compose bc !ab+  | null bc = empty+  | otherwise = mapMaybe (bc !?) ab++{--------------------------------------------------------------------   Construction --------------------------------------------------------------------} -- | /O(1)/. The empty map.@@ -1825,8 +1854,9 @@   :: Applicative f => (Key -> a -> f Bool) -> IntMap a -> f (IntMap a) filterWithKeyA _ Nil           = pure Nil filterWithKeyA f t@(Tip k x)   = (\b -> if b then t else Nil) <$> f k x-filterWithKeyA f (Bin p m l r) =-    liftA2 (bin p m) (filterWithKeyA f l) (filterWithKeyA f r)+filterWithKeyA f (Bin p m l r)+  | m < 0     = liftA2 (flip (bin p m)) (filterWithKeyA f r) (filterWithKeyA f l)+  | otherwise = liftA2 (bin p m) (filterWithKeyA f l) (filterWithKeyA f r)  -- | This wasn't in Data.Bool until 4.7.0, so we define it here bool :: a -> a -> Bool -> a@@ -1867,7 +1897,9 @@     where     go Nil           = pure Nil     go (Tip k x)     = maybe Nil (Tip k) <$> f k x-    go (Bin p m l r) = liftA2 (bin p m) (go l) (go r)+    go (Bin p m l r)+      | m < 0     = liftA2 (flip (bin p m)) (go r) (go l)+      | otherwise = liftA2 (bin p m) (go l) (go r)   -- | Merge two maps.@@ -2039,8 +2071,8 @@       where         merge2 t2@(Bin p2 m2 l2 r2)           | nomatch k1 p2 m2 = linkA k1 (subsingletonBy g1k k1 x1) p2 (g2t t2)-          | zero k1 m2       = liftA2 (bin p2 m2) (merge2 l2) (g2t r2)-          | otherwise        = liftA2 (bin p2 m2) (g2t l2) (merge2 r2)+          | zero k1 m2       = binA p2 m2 (merge2 l2) (g2t r2)+          | otherwise        = binA p2 m2 (g2t l2) (merge2 r2)         merge2 (Tip k2 x2)   = mergeTips k1 x1 k2 x2         merge2 Nil           = subsingletonBy g1k k1 x1 @@ -2048,23 +2080,23 @@       where         merge1 t1@(Bin p1 m1 l1 r1)           | nomatch k2 p1 m1 = linkA p1 (g1t t1) k2 (subsingletonBy g2k k2 x2)-          | zero k2 m1       = liftA2 (bin p1 m1) (merge1 l1) (g1t r1)-          | otherwise        = liftA2 (bin p1 m1) (g1t l1) (merge1 r1)+          | zero k2 m1       = binA p1 m1 (merge1 l1) (g1t r1)+          | otherwise        = binA p1 m1 (g1t l1) (merge1 r1)         merge1 (Tip k1 x1)   = mergeTips k1 x1 k2 x2         merge1 Nil           = subsingletonBy g2k k2 x2      go t1@(Bin p1 m1 l1 r1) t2@(Bin p2 m2 l2 r2)       | shorter m1 m2  = merge1       | shorter m2 m1  = merge2-      | p1 == p2       = liftA2 (bin p1 m1)   (go  l1 l2) (go r1 r2)-      | otherwise      = liftA2 (link_ p1 p2) (g1t t1)    (g2t   t2)+      | p1 == p2       = binA p1 m1 (go l1 l2) (go r1 r2)+      | otherwise      = linkA p1 (g1t t1) p2 (g2t t2)       where-        merge1 | nomatch p2 p1 m1  = liftA2 (link_ p1 p2) (g1t t1)    (g2t t2)-               | zero p2 m1        = liftA2 (bin p1 m1)   (go  l1 t2) (g1t r1)-               | otherwise         = liftA2 (bin p1 m1)   (g1t l1)    (go  r1 t2)-        merge2 | nomatch p1 p2 m2  = liftA2 (link_ p1 p2) (g1t t1)    (g2t    t2)-               | zero p1 m2        = liftA2 (bin p2 m2)   (go  t1 l2) (g2t    r2)-               | otherwise         = liftA2 (bin p2 m2)   (g2t    l2) (go  t1 r2)+        merge1 | nomatch p2 p1 m1  = linkA p1 (g1t t1) p2 (g2t t2)+               | zero p2 m1        = binA p1 m1 (go  l1 t2) (g1t r1)+               | otherwise         = binA p1 m1 (g1t l1)    (go  r1 t2)+        merge2 | nomatch p1 p2 m2  = linkA p1 (g1t t1) p2 (g2t t2)+               | zero p1 m2        = binA p2 m2 (go  t1 l2) (g2t    r2)+               | otherwise         = binA p2 m2 (g2t    l2) (go  t1 r2)      subsingletonBy gk k x = maybe Nil (Tip k) <$> gk k x     {-# INLINE subsingletonBy #-}@@ -2084,11 +2116,6 @@     subdoubleton k1 k2 (Just y1) (Just y2) = link k1 (Tip k1 y1) k2 (Tip k2 y2)     {-# INLINE subdoubleton #-} -    link_ _  _  Nil t2  = t2-    link_ _  _  t1  Nil = t1-    link_ p1 p2 t1  t2  = link p1 t1 p2 t2-    {-# INLINE link_ #-}-     -- | A variant of 'link_' which makes sure to execute side-effects     -- in the right order.     linkA@@ -2097,12 +2124,26 @@         -> Prefix -> f (IntMap a)         -> f (IntMap a)     linkA p1 t1 p2 t2-      | zero p1 m = liftA2 (bin p m) t1 t2-      | otherwise = liftA2 (bin p m) t2 t1+      | zero p1 m = binA p m t1 t2+      | otherwise = binA p m t2 t1       where         m = branchMask p1 p2         p = mask p1 m     {-# INLINE linkA #-}++    -- A variant of 'bin' that ensures that effects for negative keys are executed+    -- first.+    binA+        :: Applicative f+        => Prefix+        -> Mask+        -> f (IntMap a)+        -> f (IntMap a)+        -> f (IntMap a)+    binA p m a b+      | m < 0     = liftA2 (flip (bin p m)) b a+      | otherwise = liftA2       (bin p m)  a b+    {-# INLINE binA #-} {-# INLINE mergeA #-}  @@ -2309,7 +2350,7 @@  {- | /O(n+m)/. Is this a proper submap? (ie. a submap but not equal).  The expression (@'isProperSubmapOfBy' f m1 m2@) returns 'True' when- @m1@ and @m2@ are not equal,+ @keys m1@ and @keys m2@ are not equal,  all keys in @m1@ are in @m2@, and when @f@ returns 'True' when  applied to their respective values. For example, the following  expressions are all 'True':@@ -2456,7 +2497,7 @@     go Nil = pure Nil     go (Tip k v) = Tip k <$> f k v     go (Bin p m l r)-      | m < 0     = liftA2 (Bin p m) (go r) (go l)+      | m < 0     = liftA2 (flip (Bin p m)) (go r) (go l)       | otherwise = liftA2 (Bin p m) (go l) (go r) {-# INLINE traverseWithKey #-} @@ -2484,20 +2525,32 @@ mapAccumL :: (a -> Key -> b -> (a,c)) -> a -> IntMap b -> (a,IntMap c) mapAccumL f a t   = case t of-      Bin p m l r -> let (a1,l') = mapAccumL f a l-                         (a2,r') = mapAccumL f a1 r-                     in (a2,Bin p m l' r')+      Bin p m l r+        | m < 0 ->+            let (a1,r') = mapAccumL f a r+                (a2,l') = mapAccumL f a1 l+            in (a2,Bin p m l' r')+        | otherwise  ->+            let (a1,l') = mapAccumL f a l+                (a2,r') = mapAccumL f a1 r+            in (a2,Bin p m l' r')       Tip k x     -> let (a',x') = f a k x in (a',Tip k x')       Nil         -> (a,Nil) --- | /O(n)/. The function @'mapAccumR'@ threads an accumulating+-- | /O(n)/. The function @'mapAccumRWithKey'@ threads an accumulating -- argument through the map in descending order of keys. mapAccumRWithKey :: (a -> Key -> b -> (a,c)) -> a -> IntMap b -> (a,IntMap c) mapAccumRWithKey f a t   = case t of-      Bin p m l r -> let (a1,r') = mapAccumRWithKey f a r-                         (a2,l') = mapAccumRWithKey f a1 l-                     in (a2,Bin p m l' r')+      Bin p m l r+        | m < 0 ->+            let (a1,l') = mapAccumRWithKey f a l+                (a2,r') = mapAccumRWithKey f a1 r+            in (a2,Bin p m l' r')+        | otherwise  ->+            let (a1,r') = mapAccumRWithKey f a r+                (a2,l') = mapAccumRWithKey f a1 l+            in (a2,Bin p m l' r')       Tip k x     -> let (a',x') = f a k x in (a',Tip k x')       Nil         -> (a,Nil) @@ -3111,8 +3164,8 @@ -- > fromAscList [(3,"b"), (5,"a"), (5,"b")] == fromList [(3, "b"), (5, "b")]  fromAscList :: [(Key,a)] -> IntMap a-fromAscList xs-  = fromAscListWithKey (\_ x _ -> x) xs+fromAscList = fromMonoListWithKey Nondistinct (\_ x _ -> x)+{-# NOINLINE fromAscList #-}  -- | /O(n)/. Build a map from a list of key\/value pairs where -- the keys are in ascending order, with a combining function on equal keys.@@ -3121,8 +3174,8 @@ -- > fromAscListWith (++) [(3,"b"), (5,"a"), (5,"b")] == fromList [(3, "b"), (5, "ba")]  fromAscListWith :: (a -> a -> a) -> [(Key,a)] -> IntMap a-fromAscListWith f xs-  = fromAscListWithKey (\_ x y -> f x y) xs+fromAscListWith f = fromMonoListWithKey Nondistinct (\_ x y -> f x y)+{-# NOINLINE fromAscListWith #-}  -- | /O(n)/. Build a map from a list of key\/value pairs where -- the keys are in ascending order, with a combining function on equal keys.@@ -3132,14 +3185,8 @@ -- > fromAscListWithKey f [(3,"b"), (5,"a"), (5,"b")] == fromList [(3, "b"), (5, "5:b|a")]  fromAscListWithKey :: (Key -> a -> a -> a) -> [(Key,a)] -> IntMap a-fromAscListWithKey _ []         = Nil-fromAscListWithKey f (x0 : xs0) = fromDistinctAscList (combineEq x0 xs0)-  where-    -- [combineEq f xs] combines equal elements with function [f] in an ordered list [xs]-    combineEq z [] = [z]-    combineEq z@(kz,zz) (x@(kx,xx):xs)-      | kx==kz    = let yy = f kx xx zz in combineEq (kx,yy) xs-      | otherwise = z:combineEq x xs+fromAscListWithKey f = fromMonoListWithKey Nondistinct f+{-# NOINLINE fromAscListWithKey #-}  -- | /O(n)/. Build a map from a list of key\/value pairs where -- the keys are in ascending order and all distinct.@@ -3147,36 +3194,72 @@ -- -- > fromDistinctAscList [(3,"b"), (5,"a")] == fromList [(3, "b"), (5, "a")] -#if __GLASGOW_HASKELL__-fromDistinctAscList :: forall a. [(Key,a)] -> IntMap a-#else-fromDistinctAscList ::            [(Key,a)] -> IntMap a-#endif-fromDistinctAscList []         = Nil-fromDistinctAscList (z0 : zs0) = work z0 zs0 Nada+fromDistinctAscList :: [(Key,a)] -> IntMap a+fromDistinctAscList = fromMonoListWithKey Distinct (\_ x _ -> x)+{-# NOINLINE fromDistinctAscList #-}++-- | /O(n)/. Build a map from a list of key\/value pairs with monotonic keys+-- and a combining function.+--+-- The precise conditions under which this function works are subtle:+-- For any branch mask, keys with the same prefix w.r.t. the branch+-- mask must occur consecutively in the list.++fromMonoListWithKey :: Distinct -> (Key -> a -> a -> a) -> [(Key,a)] -> IntMap a+fromMonoListWithKey distinct f = go   where-    work (kx,vx) []            stk = finish kx (Tip kx vx) stk-    work (kx,vx) (z@(kz,_):zs) stk = reduce z zs (branchMask kx kz) kx (Tip kx vx) stk+    go []              = Nil+    go ((kx,vx) : zs1) = addAll' kx vx zs1 -#if __GLASGOW_HASKELL__-    reduce :: (Key,a) -> [(Key,a)] -> Mask -> Prefix -> IntMap a -> Stack a -> IntMap a-#endif-    reduce z zs _ px tx Nada = work z zs (Push px tx Nada)-    reduce z zs m px tx stk@(Push py ty stk') =-        let mxy = branchMask px py-            pxy = mask px mxy-        in  if shorter m mxy-            then reduce z zs m pxy (Bin pxy mxy ty tx) stk'-            else work z zs (Push px tx stk)+    -- `addAll'` collects all keys equal to `kx` into a single value,+    -- and then proceeds with `addAll`.+    addAll' !kx vx []+        = Tip kx vx+    addAll' !kx vx ((ky,vy) : zs)+        | Nondistinct <- distinct, kx == ky+        = let v = f kx vy vx in addAll' ky v zs+        -- inlined: | otherwise = addAll kx (Tip kx vx) (ky : zs)+        | m <- branchMask kx ky+        , Inserted ty zs' <- addMany' m ky vy zs+        = addAll kx (linkWithMask m ky ty {-kx-} (Tip kx vx)) zs' -    finish _  t  Nada = t-    finish px tx (Push py ty stk) = finish p (link py ty px tx) stk-        where m = branchMask px py-              p = mask px m+    -- for `addAll` and `addMany`, kx is /a/ key inside the tree `tx`+    -- `addAll` consumes the rest of the list, adding to the tree `tx`+    addAll !_kx !tx []+        = tx+    addAll !kx !tx ((ky,vy) : zs)+        | m <- branchMask kx ky+        , Inserted ty zs' <- addMany' m ky vy zs+        = addAll kx (linkWithMask m ky ty {-kx-} tx) zs' -data Stack a = Push {-# UNPACK #-} !Prefix !(IntMap a) !(Stack a) | Nada+    -- `addMany'` is similar to `addAll'`, but proceeds with `addMany'`.+    addMany' !_m !kx vx []+        = Inserted (Tip kx vx) []+    addMany' !m !kx vx zs0@((ky,vy) : zs)+        | Nondistinct <- distinct, kx == ky+        = let v = f kx vy vx in addMany' m ky v zs+        -- inlined: | otherwise = addMany m kx (Tip kx vx) (ky : zs)+        | mask kx m /= mask ky m+        = Inserted (Tip kx vx) zs0+        | mxy <- branchMask kx ky+        , Inserted ty zs' <- addMany' mxy ky vy zs+        = addMany m kx (linkWithMask mxy ky ty {-kx-} (Tip kx vx)) zs' +    -- `addAll` adds to `tx` all keys whose prefix w.r.t. `m` agrees with `kx`.+    addMany !_m !_kx tx []+        = Inserted tx []+    addMany !m !kx tx zs0@((ky,vy) : zs)+        | mask kx m /= mask ky m+        = Inserted tx zs0+        | mxy <- branchMask kx ky+        , Inserted ty zs' <- addMany' mxy ky vy zs+        = addMany m kx (linkWithMask mxy ky ty {-kx-} tx) zs'+{-# INLINE fromMonoListWithKey #-} +data Inserted a = Inserted !(IntMap a) ![(Key,a)]++data Distinct = Distinct | Nondistinct+ {--------------------------------------------------------------------   Eq --------------------------------------------------------------------}@@ -3297,13 +3380,17 @@   Link --------------------------------------------------------------------} link :: Prefix -> IntMap a -> Prefix -> IntMap a -> IntMap a-link p1 t1 p2 t2+link p1 t1 p2 t2 = linkWithMask (branchMask p1 p2) p1 t1 {-p2-} t2+{-# INLINE link #-}++-- `linkWithMask` is useful when the `branchMask` has already been computed+linkWithMask :: Mask -> Prefix -> IntMap a -> IntMap a -> IntMap a+linkWithMask m p1 t1 {-p2-} t2   | zero p1 m = Bin p m t1 t2   | otherwise = Bin p m t2 t1   where-    m = branchMask p1 p2     p = mask p1 m-{-# INLINE link #-}+{-# INLINE linkWithMask #-}  {--------------------------------------------------------------------   @bin@ assures that we never have empty trees within a tree.
src/Data/IntMap/Lazy.hs view
@@ -58,7 +58,7 @@ -- --    * Chris Okasaki and Andy Gill,  \"/Fast Mergeable Integer Maps/\", --      Workshop on ML, September 1998, pages 77-86,---      <http://citeseer.ist.psu.edu/okasaki98fast.html>+--      <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.37.5452> -- --    * D.R. Morrison, \"/PATRICIA -- Practical Algorithm To Retrieve --      Information Coded In Alphanumeric/\", Journal of the ACM, 15(4),@@ -145,6 +145,9 @@      -- ** Disjoint     , disjoint++    -- ** Compose+    , compose      -- ** Universal combining function     , mergeWithKey
src/Data/IntMap/Strict.hs view
@@ -75,7 +75,7 @@ -- --    * Chris Okasaki and Andy Gill,  \"/Fast Mergeable Integer Maps/\", --      Workshop on ML, September 1998, pages 77-86,---      <http://citeseer.ist.psu.edu/okasaki98fast.html>+--      <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.37.5452> -- --    * D.R. Morrison, \"/PATRICIA -- Practical Algorithm To Retrieve --      Information Coded In Alphanumeric/\", Journal of the ACM, 15(4),@@ -164,6 +164,9 @@      -- ** Disjoint     , disjoint++    -- ** Compose+    , compose      -- ** Universal combining function     , mergeWithKey
src/Data/IntMap/Strict/Internal.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE PatternGuards #-}  #include "containers.h" @@ -72,7 +73,7 @@ -- --    * Chris Okasaki and Andy Gill,  \"/Fast Mergeable Integer Maps/\", --      Workshop on ML, September 1998, pages 77-86,---      <http://citeseer.ist.psu.edu/okasaki98fast.html>+--      <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.37.5452> -- --    * D.R. Morrison, \"/PATRICIA -- Practical Algorithm To Retrieve --      Information Coded In Alphanumeric/\", Journal of the ACM, 15(4),@@ -162,6 +163,9 @@     -- ** Disjoint     , disjoint +    -- ** Compose+    , compose+     -- ** Universal combining function     , mergeWithKey @@ -257,11 +261,8 @@ import Data.IntMap.Internal   ( IntMap (..)   , Key-  , Prefix-  , Mask   , mask   , branchMask-  , shorter   , nomatch   , zero   , natFromInt@@ -270,6 +271,7 @@   , binCheckLeft   , binCheckRight   , link+  , linkWithMask    , (\\)   , (!)@@ -717,6 +719,27 @@   = mergeWithKey' bin (\(Tip k1 x1) (Tip _k2 x2) -> Tip k1 $! f k1 x1 x2) (const Nil) (const Nil) m1 m2  {--------------------------------------------------------------------+  Compose+--------------------------------------------------------------------}+-- | Relate the keys of one map to the values of+-- the other, by using the values of the former as keys for lookups+-- in the latter.+--+-- Complexity: \( O(n * \min(m,W)) \), where \(m\) is the size of the first argument+--+-- > compose (fromList [('a', "A"), ('b', "B")]) (fromList [(1,'a'),(2,'b'),(3,'z')]) = fromList [(1,"A"),(2,"B")]+--+-- @+-- ('compose' bc ab '!?') = (bc '!?') <=< (ab '!?')+-- @+--+-- @since 0.6.3.1+compose :: IntMap c -> IntMap Int -> IntMap c+compose bc !ab+  | null bc = empty+  | otherwise = mapMaybe (bc !?) ab++{--------------------------------------------------------------------   MergeWithKey --------------------------------------------------------------------} @@ -894,7 +917,9 @@   where     go Nil = pure Nil     go (Tip k v) = (\ !v' -> Tip k v') <$> f k v-    go (Bin p m l r) = liftA2 (Bin p m) (go l) (go r)+    go (Bin p m l r)+      | m < 0     = liftA2 (flip (Bin p m)) (go r) (go l)+      | otherwise = liftA2 (Bin p m) (go l) (go r) {-# INLINE traverseWithKey #-}  -- | /O(n)/. Traverse keys\/values and collect the 'Just' results.@@ -904,7 +929,9 @@     where     go Nil           = pure Nil     go (Tip k x)     = maybe Nil (Tip k $!) <$> f k x-    go (Bin p m l r) = liftA2 (bin p m) (go l) (go r)+    go (Bin p m l r)+      | m < 0     = liftA2 (flip (bin p m)) (go r) (go l)+      | otherwise = liftA2 (bin p m) (go l) (go r)  -- | /O(n)/. The function @'mapAccum'@ threads an accumulating -- argument through the map in ascending order of keys.@@ -934,22 +961,34 @@   where     go f a t       = case t of-          Bin p m l r -> let (a1 :*: l') = go f a l-                             (a2 :*: r') = go f a1 r-                         in (a2 :*: Bin p m l' r')+          Bin p m l r+            | m < 0 ->+                let (a1 :*: r') = go f a r+                    (a2 :*: l') = go f a1 l+                in (a2 :*: Bin p m l' r')+            | otherwise ->+                let (a1 :*: l') = go f a l+                    (a2 :*: r') = go f a1 r+                in (a2 :*: Bin p m l' r')           Tip k x     -> let !(a',!x') = f a k x in (a' :*: Tip k x')           Nil         -> (a :*: Nil) --- | /O(n)/. The function @'mapAccumR'@ threads an accumulating+-- | /O(n)/. The function @'mapAccumRWithKey'@ threads an accumulating -- argument through the map in descending order of keys. mapAccumRWithKey :: (a -> Key -> b -> (a,c)) -> a -> IntMap b -> (a,IntMap c) mapAccumRWithKey f0 a0 t0 = toPair $ go f0 a0 t0   where     go f a t       = case t of-          Bin p m l r -> let (a1 :*: r') = go f a r-                             (a2 :*: l') = go f a1 l-                         in (a2 :*: Bin p m l' r')+          Bin p m l r+            | m < 0 ->+              let (a1 :*: l') = go f a l+                  (a2 :*: r') = go f a1 r+              in (a2 :*: Bin p m l' r')+            | otherwise ->+              let (a1 :*: r') = go f a r+                  (a2 :*: l') = go f a1 l+              in (a2 :*: Bin p m l' r')           Tip k x     -> let !(a',!x') = f a k x in (a' :*: Tip k x')           Nil         -> (a :*: Nil) @@ -1098,8 +1137,8 @@ -- > fromAscList [(3,"b"), (5,"a"), (5,"b")] == fromList [(3, "b"), (5, "b")]  fromAscList :: [(Key,a)] -> IntMap a-fromAscList xs-  = fromAscListWithKey (\_ x _ -> x) xs+fromAscList = fromMonoListWithKey Nondistinct (\_ x _ -> x)+{-# NOINLINE fromAscList #-}  -- | /O(n)/. Build a map from a list of key\/value pairs where -- the keys are in ascending order, with a combining function on equal keys.@@ -1108,8 +1147,8 @@ -- > fromAscListWith (++) [(3,"b"), (5,"a"), (5,"b")] == fromList [(3, "b"), (5, "ba")]  fromAscListWith :: (a -> a -> a) -> [(Key,a)] -> IntMap a-fromAscListWith f xs-  = fromAscListWithKey (\_ x y -> f x y) xs+fromAscListWith f = fromMonoListWithKey Nondistinct (\_ x y -> f x y)+{-# NOINLINE fromAscListWith #-}  -- | /O(n)/. Build a map from a list of key\/value pairs where -- the keys are in ascending order, with a combining function on equal keys.@@ -1118,14 +1157,8 @@ -- > fromAscListWith (++) [(3,"b"), (5,"a"), (5,"b")] == fromList [(3, "b"), (5, "ba")]  fromAscListWithKey :: (Key -> a -> a -> a) -> [(Key,a)] -> IntMap a-fromAscListWithKey _ []         = Nil-fromAscListWithKey f (x0 : xs0) = fromDistinctAscList (combineEq x0 xs0)-  where-    -- [combineEq f xs] combines equal elements with function [f] in an ordered list [xs]-    combineEq z [] = [z]-    combineEq z@(kz,zz) (x@(kx,xx):xs)-      | kx==kz    = let !yy = f kx xx zz in combineEq (kx,yy) xs-      | otherwise = z:combineEq x xs+fromAscListWithKey f = fromMonoListWithKey Nondistinct f+{-# NOINLINE fromAscListWithKey #-}  -- | /O(n)/. Build a map from a list of key\/value pairs where -- the keys are in ascending order and all distinct.@@ -1134,24 +1167,67 @@ -- > fromDistinctAscList [(3,"b"), (5,"a")] == fromList [(3, "b"), (5, "a")]  fromDistinctAscList :: [(Key,a)] -> IntMap a-fromDistinctAscList []         = Nil-fromDistinctAscList (z0 : zs0) = work z0 zs0 Nada+fromDistinctAscList = fromMonoListWithKey Distinct (\_ x _ -> x)+{-# NOINLINE fromDistinctAscList #-}++-- | /O(n)/. Build a map from a list of key\/value pairs with monotonic keys+-- and a combining function.+--+-- The precise conditions under which this function works are subtle:+-- For any branch mask, keys with the same prefix w.r.t. the branch+-- mask must occur consecutively in the list.++fromMonoListWithKey :: Distinct -> (Key -> a -> a -> a) -> [(Key,a)] -> IntMap a+fromMonoListWithKey distinct f = go   where-    work (kx,!vx) []            stk = finish kx (Tip kx vx) stk-    work (kx,!vx) (z@(kz,_):zs) stk = reduce z zs (branchMask kx kz) kx (Tip kx vx) stk+    go []              = Nil+    go ((kx,vx) : zs1) = addAll' kx vx zs1 -    reduce :: (Key,a) -> [(Key,a)] -> Mask -> Prefix -> IntMap a -> Stack a -> IntMap a-    reduce z zs _ px tx Nada = work z zs (Push px tx Nada)-    reduce z zs m px tx stk@(Push py ty stk') =-        let mxy = branchMask px py-            pxy = mask px mxy-        in  if shorter m mxy-                 then reduce z zs m pxy (Bin pxy mxy ty tx) stk'-                 else work z zs (Push px tx stk)+    -- `addAll'` collects all keys equal to `kx` into a single value,+    -- and then proceeds with `addAll`.+    addAll' !kx vx []+        = Tip kx $! vx+    addAll' !kx vx ((ky,vy) : zs)+        | Nondistinct <- distinct, kx == ky+        = let !v = f kx vy vx in addAll' ky v zs+        -- inlined: | otherwise = addAll kx (Tip kx $! vx) (ky : zs)+        | m <- branchMask kx ky+        , Inserted ty zs' <- addMany' m ky vy zs+        = addAll kx (linkWithMask m ky ty {-kx-} (Tip kx $! vx)) zs' -    finish _  t  Nada = t-    finish px tx (Push py ty stk) = finish p (link py ty px tx) stk-        where m = branchMask px py-              p = mask px m+    -- for `addAll` and `addMany`, kx is /a/ key inside the tree `tx`+    -- `addAll` consumes the rest of the list, adding to the tree `tx`+    addAll !_kx !tx []+        = tx+    addAll !kx !tx ((ky,vy) : zs)+        | m <- branchMask kx ky+        , Inserted ty zs' <- addMany' m ky vy zs+        = addAll kx (linkWithMask m ky ty {-kx-} tx) zs' -data Stack a = Push {-# UNPACK #-} !Prefix !(IntMap a) !(Stack a) | Nada+    -- `addMany'` is similar to `addAll'`, but proceeds with `addMany'`.+    addMany' !_m !kx vx []+        = Inserted (Tip kx $! vx) []+    addMany' !m !kx vx zs0@((ky,vy) : zs)+        | Nondistinct <- distinct, kx == ky+        = let !v = f kx vy vx in addMany' m ky v zs+        -- inlined: | otherwise = addMany m kx (Tip kx $! vx) (ky : zs)+        | mask kx m /= mask ky m+        = Inserted (Tip kx $! vx) zs0+        | mxy <- branchMask kx ky+        , Inserted ty zs' <- addMany' mxy ky vy zs+        = addMany m kx (linkWithMask mxy ky ty {-kx-} (Tip kx $! vx)) zs'++    -- `addAll` adds to `tx` all keys whose prefix w.r.t. `m` agrees with `kx`.+    addMany !_m !_kx tx []+        = Inserted tx []+    addMany !m !kx tx zs0@((ky,vy) : zs)+        | mask kx m /= mask ky m+        = Inserted tx zs0+        | mxy <- branchMask kx ky+        , Inserted ty zs' <- addMany' mxy ky vy zs+        = addMany m kx (linkWithMask mxy ky ty {-kx-} tx) zs'+{-# INLINE fromMonoListWithKey #-}++data Inserted a = Inserted !(IntMap a) ![(Key,a)]++data Distinct = Distinct | Nondistinct
src/Data/IntSet.hs view
@@ -47,7 +47,7 @@ -- --    * Chris Okasaki and Andy Gill,  \"/Fast Mergeable Integer Maps/\", --      Workshop on ML, September 1998, pages 77-86,---      <http://citeseer.ist.psu.edu/okasaki98fast.html>+--      <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.37.5452> -- --    * D.R. Morrison, \"/PATRICIA -- Practical Algorithm To Retrieve --      Information Coded In Alphanumeric/\", Journal of the ACM, 15(4),@@ -86,6 +86,9 @@             -- * Deletion             , delete +            -- * Generalized insertion/deletion+            , alterF+             -- * Query             , member             , notMember@@ -115,6 +118,7 @@              -- * Map             , IS.map+            , mapMonotonic              -- * Folds             , IS.foldr
src/Data/IntSet/Internal.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE PatternGuards #-} #if __GLASGOW_HASKELL__ {-# LANGUAGE MagicHash, DeriveDataTypeable, StandaloneDeriving #-} #endif@@ -53,7 +54,7 @@ -- --    * Chris Okasaki and Andy Gill,  \"/Fast Mergeable Integer Maps/\", --      Workshop on ML, September 1998, pages 77-86,---      <http://citeseer.ist.psu.edu/okasaki98fast.html>+--      <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.37.5452> -- --    * D.R. Morrison, \"/PATRICIA -- Practical Algorithm To Retrieve --      Information Coded In Alphanumeric/\", Journal of the ACM, 15(4),@@ -125,6 +126,7 @@     , singleton     , insert     , delete+    , alterF      -- * Combine     , union@@ -141,6 +143,7 @@      -- * Map     , map+    , mapMonotonic      -- * Folds     , foldr@@ -186,6 +189,7 @@     , zero     ) where +import Control.Applicative (Const(..)) import Control.DeepSeq (NFData(rnf)) import Data.Bits import qualified Data.List as List@@ -210,20 +214,19 @@ import Utils.Containers.Internal.StrictPair  #if __GLASGOW_HASKELL__-import Data.Data (Data(..), Constr, mkConstr, constrIndex, Fixity(Prefix), DataType, mkDataType)+import Data.Data (Data(..), Constr, mkConstr, constrIndex, DataType, mkDataType)+import qualified Data.Data import Text.Read #endif  #if __GLASGOW_HASKELL__-import GHC.Exts (Int(..), build)-#if __GLASGOW_HASKELL__ >= 708-import qualified GHC.Exts as GHCExts-#endif-import GHC.Exts (indexInt8OffAddr#)+import qualified GHC.Exts #endif  import qualified Data.Foldable as Foldable-#if !MIN_VERSION_base(4,8,0)+#if MIN_VERSION_base(4,8,0)+import Data.Functor.Identity (Identity(..))+#else import Data.Foldable (Foldable()) #endif @@ -310,7 +313,7 @@   dataTypeOf _   = intSetDataType  fromListConstr :: Constr-fromListConstr = mkConstr intSetDataType "fromList" [] Prefix+fromListConstr = mkConstr intSetDataType "fromList" [] Data.Data.Prefix  intSetDataType :: DataType intSetDataType = mkDataType "Data.IntSet.Internal.IntSet" [fromListConstr]@@ -503,7 +506,43 @@   | otherwise = t deleteBM _ _ Nil = Nil +-- | /O(min(n,W))/. @('alterF' f x s)@ can delete or insert @x@ in @s@ depending+-- on whether it is already present in @s@.+--+-- In short:+--+-- @+-- 'member' x \<$\> 'alterF' f x s = f ('member' x s)+-- @+--+-- Note: 'alterF' is a variant of the @at@ combinator from "Control.Lens.At".+--+-- @since 0.6.3.1+alterF :: Functor f => (Bool -> f Bool) -> Key -> IntSet -> f IntSet+alterF f k s = fmap choose (f member_)+  where+    member_ = member k s +    (inserted, deleted)+      | member_   = (s         , delete k s)+      | otherwise = (insert k s, s         )++    choose True  = inserted+    choose False = deleted+#ifndef __GLASGOW_HASKELL__+{-# INLINE alterF #-}+#else+{-# INLINABLE [2] alterF #-}++{-# RULES+"alterF/Const" forall k (f :: Bool -> Const a Bool) . alterF f k = \s -> Const . getConst . f $ member k s+ #-}+#endif++#if MIN_VERSION_base(4,8,0)+{-# SPECIALIZE alterF :: (Bool -> Identity Bool) -> Key -> IntSet -> Identity IntSet #-}+#endif+ {--------------------------------------------------------------------   Union --------------------------------------------------------------------}@@ -911,6 +950,23 @@ map :: (Key -> Key) -> IntSet -> IntSet map f = fromList . List.map f . toList +-- | /O(n)/. The+--+-- @'mapMonotonic' f s == 'map' f s@, but works only when @f@ is strictly increasing.+-- /The precondition is not checked./+-- Semi-formally, we have:+--+-- > and [x < y ==> f x < f y | x <- ls, y <- ls]+-- >                     ==> mapMonotonic f s == map f s+-- >     where ls = toList s+--+-- @since 0.6.3.1++-- Note that for now the test is insufficient to support any fancier implementation.+mapMonotonic :: (Key -> Key) -> IntSet -> IntSet+mapMonotonic f = fromDistinctAscList . List.map f . toAscList++ {--------------------------------------------------------------------   Fold --------------------------------------------------------------------}@@ -999,7 +1055,7 @@ --------------------------------------------------------------------} #if __GLASGOW_HASKELL__ >= 708 -- | @since 0.5.6.2-instance GHCExts.IsList IntSet where+instance GHC.Exts.IsList IntSet where   type Item IntSet = Key   fromList = fromList   toList   = toList@@ -1043,9 +1099,9 @@ -- before phase 0, otherwise the fusion rules would not fire at all. {-# NOINLINE[0] toAscList #-} {-# NOINLINE[0] toDescList #-}-{-# RULES "IntSet.toAscList" [~1] forall s . toAscList s = build (\c n -> foldrFB c n s) #-}+{-# RULES "IntSet.toAscList" [~1] forall s . toAscList s = GHC.Exts.build (\c n -> foldrFB c n s) #-} {-# RULES "IntSet.toAscListBack" [1] foldrFB (:) [] = toAscList #-}-{-# RULES "IntSet.toDescList" [~1] forall s . toDescList s = build (\c n -> foldlFB (\xs x -> c x xs) n s) #-}+{-# RULES "IntSet.toDescList" [~1] forall s . toDescList s = GHC.Exts.build (\c n -> foldlFB (\xs x -> c x xs) n s) #-} {-# RULES "IntSet.toDescListBack" [1] foldlFB (\xs x -> x : xs) [] = toDescList #-} #endif @@ -1060,41 +1116,74 @@ -- | /O(n)/. Build a set from an ascending list of elements. -- /The precondition (input list is ascending) is not checked./ fromAscList :: [Key] -> IntSet-fromAscList [] = Nil-fromAscList (x0 : xs0) = fromDistinctAscList (combineEq x0 xs0)-  where-    combineEq x' [] = [x']-    combineEq x' (x:xs)-      | x==x'     = combineEq x' xs-      | otherwise = x' : combineEq x xs+fromAscList = fromMonoList+{-# NOINLINE fromAscList #-}  -- | /O(n)/. Build a set from an ascending list of distinct elements. -- /The precondition (input list is strictly ascending) is not checked./ fromDistinctAscList :: [Key] -> IntSet-fromDistinctAscList []         = Nil-fromDistinctAscList (z0 : zs0) = work (prefixOf z0) (bitmapOf z0) zs0 Nada+fromDistinctAscList = fromAscList+{-# INLINE fromDistinctAscList #-}++-- | /O(n)/. Build a set from a monotonic list of elements.+--+-- The precise conditions under which this function works are subtle:+-- For any branch mask, keys with the same prefix w.r.t. the branch+-- mask must occur consecutively in the list.+fromMonoList :: [Key] -> IntSet+fromMonoList []         = Nil+fromMonoList (kx : zs1) = addAll' (prefixOf kx) (bitmapOf kx) zs1   where-    -- 'work' accumulates all values that go into one tip, before passing this Tip-    -- to 'reduce'-    work kx bm []     stk = finish kx (Tip kx bm) stk-    work kx bm (z:zs) stk | kx == prefixOf z = work kx (bm .|. bitmapOf z) zs stk-    work kx bm (z:zs) stk = reduce z zs (branchMask z kx) kx (Tip kx bm) stk+    -- `addAll'` collects all keys with the prefix `px` into a single+    -- bitmap, and then proceeds with `addAll`.+    addAll' !px !bm []+        = Tip px bm+    addAll' !px !bm (ky : zs)+        | px == prefixOf ky+        = addAll' px (bm .|. bitmapOf ky) zs+        -- inlined: | otherwise = addAll px (Tip px bm) (ky : zs)+        | py <- prefixOf ky+        , m <- branchMask px py+        , Inserted ty zs' <- addMany' m py (bitmapOf ky) zs+        = addAll px (linkWithMask m py ty {-px-} (Tip px bm)) zs' -    reduce z zs _ px tx Nada = work (prefixOf z) (bitmapOf z) zs (Push px tx Nada)-    reduce z zs m px tx stk@(Push py ty stk') =-        let mxy = branchMask px py-            pxy = mask px mxy-        in  if shorter m mxy-                 then reduce z zs m pxy (Bin pxy mxy ty tx) stk'-                 else work (prefixOf z) (bitmapOf z) zs (Push px tx stk)+    -- for `addAll` and `addMany`, px is /a/ prefix inside the tree `tx`+    -- `addAll` consumes the rest of the list, adding to the tree `tx`+    addAll !_px !tx []+        = tx+    addAll !px !tx (ky : zs)+        | py <- prefixOf ky+        , m <- branchMask px py+        , Inserted ty zs' <- addMany' m py (bitmapOf ky) zs+        = addAll px (linkWithMask m py ty {-px-} tx) zs' -    finish _  t  Nada = t-    finish px tx (Push py ty stk) = finish p (link py ty px tx) stk-        where m = branchMask px py-              p = mask px m+    -- `addMany'` is similar to `addAll'`, but proceeds with `addMany'`.+    addMany' !_m !px !bm []+        = Inserted (Tip px bm) []+    addMany' !m !px !bm zs0@(ky : zs)+        | px == prefixOf ky+        = addMany' m px (bm .|. bitmapOf ky) zs+        -- inlined: | otherwise = addMany m px (Tip px bm) (ky : zs)+        | mask px m /= mask ky m+        = Inserted (Tip (prefixOf px) bm) zs0+        | py <- prefixOf ky+        , mxy <- branchMask px py+        , Inserted ty zs' <- addMany' mxy py (bitmapOf ky) zs+        = addMany m px (linkWithMask mxy py ty {-px-} (Tip px bm)) zs' -data Stack = Push {-# UNPACK #-} !Prefix !IntSet !Stack | Nada+    -- `addAll` adds to `tx` all keys whose prefix w.r.t. `m` agrees with `px`.+    addMany !_m !_px tx []+        = Inserted tx []+    addMany !m !px tx zs0@(ky : zs)+        | mask px m /= mask ky m+        = Inserted tx zs0+        | py <- prefixOf ky+        , mxy <- branchMask px py+        , Inserted ty zs' <- addMany' mxy py (bitmapOf ky) zs+        = addMany m px (linkWithMask mxy py ty {-px-} tx) zs'+{-# INLINE fromMonoList #-} +data Inserted = Inserted !IntSet ![Key]  {--------------------------------------------------------------------   Eq@@ -1124,9 +1213,157 @@ --------------------------------------------------------------------}  instance Ord IntSet where-    compare s1 s2 = compare (toAscList s1) (toAscList s2)-    -- tentative implementation. See if more efficient exists.+  compare Nil Nil = EQ+  compare Nil _ = LT+  compare _ Nil = GT+  compare t1@(Tip _ _) t2@(Tip _ _)+    = orderingOf $ relateTipTip t1 t2+  compare xs ys+    | (xsNeg, xsNonNeg) <- splitSign xs+    , (ysNeg, ysNonNeg) <- splitSign ys+    = case relate xsNeg ysNeg of+       Less -> LT+       Prefix -> if null xsNonNeg then LT else GT+       Equals -> orderingOf (relate xsNonNeg ysNonNeg)+       FlipPrefix -> if null ysNonNeg then GT else LT+       Greater -> GT +-- | detailed outcome of lexicographic comparison of lists.+-- w.r.t. Ordering, there are two extra cases,+-- since (++) is not monotonic w.r.t. lex. order on lists+-- (which is used by definition):+-- consider comparison of  (Bin [0,3,4] [ 6] ) to  (Bin [0,3] [7] )+-- where [0,3,4] > [0,3]  but [0,3,4,6] < [0,3,7].++data Relation+  = Less  -- ^ holds for [0,3,4] [0,3,5,1]+  | Prefix -- ^ holds for [0,3,4] [0,3,4,5]+  | Equals -- ^  holds for [0,3,4] [0,3,4]+  | FlipPrefix -- ^ holds for [0,3,4] [0,3]+  | Greater -- ^ holds for [0,3,4] [0,2,5]+  deriving (Show, Eq)+   +orderingOf :: Relation -> Ordering+{-# INLINE orderingOf #-}+orderingOf r = case r of+  Less -> LT+  Prefix -> LT+  Equals -> EQ+  FlipPrefix -> GT+  Greater -> GT++-- | precondition: each argument is non-mixed+relate :: IntSet -> IntSet -> Relation+relate Nil Nil = Equals+relate Nil _t2 = Prefix+relate _t1 Nil = FlipPrefix+relate t1@Tip{} t2@Tip{} = relateTipTip t1 t2+relate t1@(Bin _p1 m1 l1 r1) t2@(Bin _p2 m2 l2 r2)+  | succUpperbound t1 <= lowerbound t2 = Less+  | lowerbound t1 >= succUpperbound t2 = Greater+  | otherwise = case compare (natFromInt m1) (natFromInt m2) of+      GT -> combine_left (relate l1 t2)+      EQ -> combine (relate l1 l2) (relate r1 r2)+      LT -> combine_right (relate t1 l2)+relate t1@(Bin _p1 m1 l1 _r1) t2@(Tip p2 _bm2)+  | succUpperbound t1 <= lowerbound t2 = Less+  | lowerbound t1 >= succUpperbound t2 = Greater+  | 0 == (m1 .&. p2) = combine_left (relate l1 t2)+  | otherwise = Less+relate t1@(Tip p1 _bm1) t2@(Bin _p2 m2 l2 _r2)+  | succUpperbound t1 <= lowerbound t2 = Less+  | lowerbound t1 >= succUpperbound t2 = Greater+  | 0 == (p1 .&. m2) = combine_right (relate t1 l2)+  | otherwise = Greater++relateTipTip :: IntSet -> IntSet -> Relation+{-# INLINE relateTipTip #-}+relateTipTip (Tip p1 bm1) (Tip p2 bm2) = case compare p1 p2 of+  LT -> Less+  EQ -> relateBM bm1 bm2+  GT -> Greater+relateTipTip _ _ = error "relateTipTip"++relateBM :: BitMap -> BitMap -> Relation+{-# inline relateBM #-}+relateBM w1 w2 | w1 == w2 = Equals+relateBM w1 w2 =+  let delta = xor w1 w2+      lowest_diff_mask = delta .&. complement (delta-1)+      prefix = (complement lowest_diff_mask + 1)+            .&. (complement lowest_diff_mask)+  in  if 0 == lowest_diff_mask .&. w1+      then if 0 == w1 .&. prefix+           then Prefix else Greater+      else if 0 == w2 .&. prefix+           then FlipPrefix else Less++-- | This function has the property+-- relate t1@(Bin p m l1 r1) t2@(Bin p m l2 r2) = combine (relate l1 l2) (relate r1 r2)+-- It is important that `combine` is lazy in the second argument (achieved by inlining)+combine :: Relation -> Relation -> Relation+{-# inline combine #-}+combine r eq = case r of+      Less -> Less+      Prefix -> Greater+      Equals -> eq+      FlipPrefix -> Less+      Greater -> Greater++-- | This function has the property+-- relate t1@(Bin p1 m1 l1 r1) t2 = combine_left (relate l1 t2)+-- under the precondition that the range of l1 contains the range of t2,+-- and r1 is non-empty+combine_left :: Relation -> Relation+{-# inline combine_left #-}+combine_left r = case r of+      Less -> Less+      Prefix -> Greater+      Equals -> FlipPrefix+      FlipPrefix -> FlipPrefix+      Greater -> Greater++-- | This function has the property+-- relate t1 t2@(Bin p2 m2 l2 r2) = combine_right (relate t1 l2)+-- under the precondition that the range of t1 is included in the range of l2,+-- and r2 is non-empty+combine_right :: Relation -> Relation+{-# inline combine_right #-}+combine_right r = case r of+      Less -> Less+      Prefix -> Prefix+      Equals -> Prefix+      FlipPrefix -> Less+      Greater -> Greater++-- | shall only be applied to non-mixed non-Nil trees+lowerbound :: IntSet -> Int+{-# INLINE lowerbound #-}+lowerbound Nil = error "lowerbound: Nil"+lowerbound (Tip p _) = p+lowerbound (Bin p _ _ _) = p++-- | this is one more than the actual upper bound (to save one operation)+-- shall only be applied to non-mixed non-Nil trees+succUpperbound :: IntSet -> Int+{-# INLINE succUpperbound #-}+succUpperbound Nil = error "succUpperbound: Nil"+succUpperbound (Tip p _) = p + wordSize +succUpperbound (Bin p m _ _) = p + shiftR m 1++-- | split a set into subsets of negative and non-negative elements+splitSign :: IntSet -> (IntSet,IntSet)+{-# INLINE splitSign #-}+splitSign t@(Tip kx _)+  | kx >= 0 = (Nil, t)+  | otherwise = (t, Nil)+splitSign t@(Bin p m l r)+  -- m < 0 is the usual way to find out if we have positives and negatives (see findMax)+  | m < 0 = (r, l)+  | p < 0 = (t, Nil)+  | otherwise = (Nil, t)+splitSign Nil = (Nil, Nil)+ {--------------------------------------------------------------------   Show --------------------------------------------------------------------}@@ -1249,13 +1486,17 @@   Link --------------------------------------------------------------------} link :: Prefix -> IntSet -> Prefix -> IntSet -> IntSet-link p1 t1 p2 t2+link p1 t1 p2 t2 = linkWithMask (branchMask p1 p2) p1 t1 {-p2-} t2+{-# INLINE link #-}++-- `linkWithMask` is useful when the `branchMask` has already been computed+linkWithMask :: Mask -> Prefix -> IntSet -> IntSet -> IntSet+linkWithMask m p1 t1 {-p2-} t2   | zero p1 m = Bin p m t1 t2   | otherwise = Bin p m t2 t1   where-    m = branchMask p1 p2     p = mask p1 m-{-# INLINE link #-}+{-# INLINE linkWithMask #-}  {--------------------------------------------------------------------   @bin@ assures that we never have empty trees within a tree.@@ -1377,6 +1618,16 @@ {-# INLINE foldr'Bits #-}  #if defined(__GLASGOW_HASKELL__) && (WORD_SIZE_IN_BITS==32 || WORD_SIZE_IN_BITS==64)+indexOfTheOnlyBit :: Nat -> Int+{-# INLINE indexOfTheOnlyBit #-}+#if MIN_VERSION_base(4,8,0) && (WORD_SIZE_IN_BITS==64)+indexOfTheOnlyBit bitmask = countTrailingZeros bitmask++lowestBitSet x = countTrailingZeros x++highestBitSet x = WORD_SIZE_IN_BITS - 1 - countLeadingZeros x++#else {----------------------------------------------------------------------   For lowestBitSet we use wordsize-dependant implementation based on   multiplication and DeBrujn indeces, which was proposed by Edward Kmett@@ -1390,11 +1641,9 @@   before changing this code. ----------------------------------------------------------------------} -indexOfTheOnlyBit :: Nat -> Int-{-# INLINE indexOfTheOnlyBit #-} indexOfTheOnlyBit bitmask =-  I# (lsbArray `indexInt8OffAddr#` unboxInt (intFromNat ((bitmask * magic) `shiftRL` offset)))-  where unboxInt (I# i) = i+  GHC.Exts.I# (lsbArray `GHC.Exts.indexInt8OffAddr#` unboxInt (intFromNat ((bitmask * magic) `shiftRL` offset)))+  where unboxInt (GHC.Exts.I# i) = i #if WORD_SIZE_IN_BITS==32         magic = 0x077CB531         offset = 27@@ -1411,6 +1660,12 @@ -- is 48B on 32-bit and 56B on 64-bit architectures -- so the 32B and 64B array -- is actually improvement on 32-bit and only a 8B size increase on 64-bit. +lowestBitSet x = indexOfTheOnlyBit (lowestBitMask x)++highestBitSet x = indexOfTheOnlyBit (highestBitMask x)++#endif+ lowestBitMask :: Nat -> Nat lowestBitMask x = x .&. negate x {-# INLINE lowestBitMask #-}@@ -1431,10 +1686,6 @@                      x5 -> case ((x5 `shiftRL` 16) .&. 0x0000FFFF0000FFFF) .|. ((x5 .&. 0x0000FFFF0000FFFF) `shiftLL` 16) of                        x6 -> ( x6 `shiftRL` 32             ) .|. ( x6               `shiftLL` 32); #endif--lowestBitSet x = indexOfTheOnlyBit (lowestBitMask x)--highestBitSet x = indexOfTheOnlyBit (highestBitMask x)  foldlBits prefix f z bitmap = go bitmap z   where go 0 acc = acc
src/Data/Map/Internal.hs view
@@ -192,6 +192,9 @@     -- ** Disjoint     , disjoint +    -- ** Compose+    , compose+     -- ** General combining function     , SimpleWhenMissing     , SimpleWhenMatched@@ -391,6 +394,9 @@ #if !MIN_VERSION_base(4,8,0) import Data.Foldable (Foldable()) #endif+#if MIN_VERSION_base(4,10,0)+import Data.Bifoldable+#endif import Data.Typeable import Prelude hiding (lookup, map, filter, foldr, foldl, null, splitAt, take, drop) @@ -1628,7 +1634,7 @@ -- | /O(log n)/. The minimal key of the map. Returns 'Nothing' if the map is empty. -- -- > lookupMin (fromList [(5,"a"), (3,"b")]) == Just (3,"b")--- > findMin empty = Nothing+-- > lookupMin empty = Nothing -- -- @since 0.5.9 @@ -2085,6 +2091,27 @@   where     (lt,found,gt) = splitMember k t +{--------------------------------------------------------------------+  Compose+--------------------------------------------------------------------}+-- | Relate the keys of one map to the values of+-- the other, by using the values of the former as keys for lookups+-- in the latter.+--+-- Complexity: \( O (n * \log(m)) \), where \(m\) is the size of the first argument+--+-- > compose (fromList [('a', "A"), ('b', "B")]) (fromList [(1,'a'),(2,'b'),(3,'z')]) = fromList [(1,"A"),(2,"B")]+--+-- @+-- ('compose' bc ab '!?') = (bc '!?') <=< (ab '!?')+-- @+--+-- @since 0.6.3.1+compose :: Ord b => Map b c -> Map a b -> Map a c+compose bc !ab+  | null bc = empty+  | otherwise = mapMaybe (bc !?) ab+ #if !MIN_VERSION_base (4,8,0) -- | The identity type. newtype Identity a = Identity { runIdentity :: a }@@ -2830,7 +2857,7 @@  {- | /O(m*log(n\/m + 1)), m <= n/. Is this a proper submap? (ie. a submap but not equal).  The expression (@'isProperSubmapOfBy' f m1 m2@) returns 'True' when- @m1@ and @m2@ are not equal,+ @keys m1@ and @keys m2@ are not equal,  all keys in @m1@ are in @m2@, and when @f@ returns 'True' when  applied to their respective values. For example, the following  expressions are all 'True':@@ -3147,7 +3174,7 @@       (a3,r') = mapAccumL f a2 r   in (a3,Bin sx kx x' l' r') --- | /O(n)/. The function 'mapAccumR' threads an accumulating+-- | /O(n)/. The function 'mapAccumRWithKey' threads an accumulating -- argument through the map in descending order of keys. mapAccumRWithKey :: (a -> k -> b -> (a,c)) -> a -> Map k b -> (a,Map k c) mapAccumRWithKey _ a Tip = (a,Tip)@@ -3949,7 +3976,7 @@ -- | /O(log n)/. Delete and find the minimal element. -- -- > deleteFindMin (fromList [(5,"a"), (3,"b"), (10,"c")]) == ((3,"b"), fromList[(5,"a"), (10,"c")])--- > deleteFindMin                                            Error: can not return the minimal element of an empty map+-- > deleteFindMin empty                                      Error: can not return the minimal element of an empty map  deleteFindMin :: Map k a -> ((k,a),Map k a) deleteFindMin t = case minViewWithKey t of@@ -4254,6 +4281,29 @@   {-# INLINABLE sum #-}   product = foldl' (*) 1   {-# INLINABLE product #-}+#endif++#if MIN_VERSION_base(4,10,0)+-- | @since 0.6.3.1+instance Bifoldable Map where+  bifold = go+    where go Tip = mempty+          go (Bin 1 k v _ _) = k `mappend` v+          go (Bin _ k v l r) = go l `mappend` (k `mappend` (v `mappend` go r))+  {-# INLINABLE bifold #-}+  bifoldr f g z = go z+    where go z' Tip             = z'+          go z' (Bin _ k v l r) = go (f k (g v (go z' r))) l+  {-# INLINE bifoldr #-}+  bifoldl f g z = go z+    where go z' Tip             = z'+          go z' (Bin _ k v l r) = go (g (f (go z' l) k) v) r+  {-# INLINE bifoldl #-}+  bifoldMap f g t = go t+    where go Tip = mempty+          go (Bin 1 k v _ _) = f k `mappend` g v+          go (Bin _ k v l r) = go l `mappend` (f k `mappend` (g v `mappend` go r))+  {-# INLINE bifoldMap #-} #endif  instance (NFData k, NFData a) => NFData (Map k a) where
src/Data/Map/Lazy.hs view
@@ -166,6 +166,9 @@     -- ** Disjoint     , disjoint +    -- ** Compose+    , compose+     -- ** General combining functions     -- | See "Data.Map.Merge.Lazy" 
src/Data/Map/Strict.hs view
@@ -182,6 +182,9 @@     -- ** Disjoint     , disjoint +    -- ** Compose+    , compose+     -- ** General combining functions     -- | See "Data.Map.Merge.Strict" 
src/Data/Map/Strict/Internal.hs view
@@ -145,6 +145,9 @@     -- ** Disjoint     , disjoint +    -- ** Compose+    , compose+     -- ** General combining function     , SimpleWhenMissing     , SimpleWhenMatched@@ -1201,6 +1204,27 @@ {-# INLINE forceMaybe #-}  {--------------------------------------------------------------------+  Compose+--------------------------------------------------------------------}+-- | Relate the keys of one map to the values of+-- the other, by using the values of the former as keys for lookups+-- in the latter.+--+-- Complexity: \( O (n * \log(m)) \), where \(m\) is the size of the first argument+--+-- > compose (fromList [('a', "A"), ('b', "B")]) (fromList [(1,'a'),(2,'b'),(3,'z')]) = fromList [(1,"A"),(2,"B")]+--+-- @+-- ('compose' bc ab '!?') = (bc '!?') <=< (ab '!?')+-- @+--+-- @since 0.6.3.1+compose :: Ord b => Map b c -> Map a b -> Map a c+compose bc !ab+  | null bc = empty+  | otherwise = mapMaybe (bc !?) ab++{--------------------------------------------------------------------   MergeWithKey --------------------------------------------------------------------} @@ -1432,7 +1456,7 @@       (a3,r') = mapAccumL f a2 r   in x' `seq` (a3,Bin sx kx x' l' r') --- | /O(n)/. The function 'mapAccumR' threads an accumulating+-- | /O(n)/. The function 'mapAccumRWithKey' threads an accumulating -- argument through the map in descending order of keys. mapAccumRWithKey :: (a -> k -> b -> (a,c)) -> a -> Map k b -> (a,Map k c) mapAccumRWithKey _ a Tip = (a,Tip)
src/Data/Sequence.hs view
@@ -102,9 +102,15 @@ -- -- Several functions take special advantage of sharing to produce -- results using much less time and memory than one might expect. These--- are documented individually for functions, but also include the--- methods '<$' and '*>', each of which take time and space proportional--- to the logarithm of the size of the result.+-- are documented individually for functions, but also include certain+-- class methods:+--+-- '<$' and '*>' each take time and space proportional+-- to the logarithm of the size of their result.+--+-- '<*' takes time and space proportional to the product of the length+-- of its first argument and the logarithm of the length of its second+-- argument. -- -- == Warning --
src/Data/Sequence/Internal.hs view
@@ -514,6 +514,7 @@ #if MIN_VERSION_base(4,10,0)     liftA2 = liftA2Seq #endif+    xs <* ys = beforeSeq xs ys  apSeq :: Seq (a -> b) -> Seq a -> Seq b apSeq fs xs@(Seq xsFT) = case viewl fs of@@ -530,7 +531,7 @@          RigidFull r@(Rigid s pr _m sf) -> Seq $                Deep (s * length fs)                     (fmap (fmap firstf) (nodeToDigit pr))-                    (aptyMiddle (fmap firstf) (fmap lastf) fmap fs''FT r)+                    (liftA2Middle (fmap firstf) (fmap lastf) fmap fs''FT r)                     (fmap (fmap lastf) (nodeToDigit sf)) {-# NOINLINE [1] apSeq #-} @@ -590,7 +591,7 @@       RigidFull r@(Rigid s pr _m sf) -> Seq $         Deep (s * length xs)              (fmap (fmap (f firstx)) (nodeToDigit pr))-             (aptyMiddle (fmap (f firstx)) (fmap (f lastx)) (lift_elem f) xs''FT r)+             (liftA2Middle (fmap (f firstx)) (fmap (f lastx)) (lift_elem f) xs''FT r)              (fmap (fmap (f lastx)) (nodeToDigit sf))   where     lift_elem :: (a -> b -> c) -> a -> Elem b -> Elem c@@ -637,65 +638,128 @@ -- digit of a 'Rigid' tree. type Digit23 a = Node a --- | 'aptyMiddle' does most of the hard work of computing @fs<*>xs@.  It+-- | 'liftA2Middle' does most of the hard work of computing @liftA2 f xs ys@.  It -- produces the center part of a finger tree, with a prefix corresponding to--- the prefix of @xs@ and a suffix corresponding to the suffix of @xs@ omitted;+-- the first element of @xs@ and a suffix corresponding to its last element omitted; -- the missing suffix and prefix are added by the caller.  For the recursive -- call, it squashes the prefix and the suffix into the center tree. Once it -- gets to the bottom, it turns the tree into a 2-3 tree, applies 'mapMulFT' to -- produce the main body, and glues all the pieces together. ----- @map23@ itself is a bit horrifying because of the nested types involved. Its+-- @f@ itself is a bit horrifying because of the nested types involved. Its -- job is to map over the *elements* of a 2-3 tree, rather than the subtrees. -- If we used a higher-order nested type with MPTC, we could probably use a--- class, but as it is we have to build up @map23@ explicitly through the+-- class, but as it is we have to build up @f@ explicitly through the -- recursion.-aptyMiddle-  :: (b -> c)-     -> (b -> c)-     -> (a -> b -> c)-     -> FingerTree (Elem a)-     -> Rigid b-     -> FingerTree (Node c)+--+-- === Description of parameters+--+-- ==== Types+--+-- @a@ remains constant through recursive calls (in the @DeepTh@ case),+-- while @b@ and @c@ do not: 'liftAMiddle' calls itself at types @Node b@ and+-- @Node c@.+--+-- ==== Values+--+-- 'liftA2Middle' is used when the original @xs :: Sequence a@ has at+-- least two elements, so it can be decomposed by taking off the first and last+-- elements:+--+-- > xs = firstx <: midxs :> lastx+--+-- - the first two arguments @ffirstx, flastx :: b -> c@ are equal to+--   @f firstx@ and @f lastx@, where @f :: a -> b -> c@ is the third argument.+--   This ensures sharing when @f@ computes some data upon being partially+--   applied to its first argument. The way @f@ gets accumulated also ensures+--   sharing for the middle section.+--+-- - the fourth argument is the middle part @midxs@, always constant.+--+-- - the last argument, a tuple of type @Rigid b@, holds all the elements of+--   @ys@, in three parts: a middle part around which the recursion is+--   structured, surrounded by a prefix and a suffix that accumulate+--   elements on the side as we walk down the middle.+--+-- === Invariants+--+-- > 1. Viewing the various trees as the lists they represent+-- >    (the types of the toList functions are given a few paragraphs below):+-- >+-- >    toListFTN result+-- >      =  (ffirstx                    <$> (toListThinN m ++ toListD sf))+-- >      ++ (f      <$> toListFTE midxs <*> (toListD pr ++ toListThinN m ++ toListD sf))+-- >      ++ (flastx                     <$> (toListD pr ++ toListThinN m))+-- >+-- > 2. s = size m + size pr + size sf+-- >+-- > 3. size (ffirstx y) = size (flastx y) = size (f x y) = size y+-- >      for any (x :: a) (y :: b)+--+-- Projecting invariant 1 on sizes, using 2 and 3 to simplify, we have the+-- following corollary.+-- It is weaker than invariant 1, but it may be easier to keep track of.+--+-- > 1a. size result = s * (size midxs + 1) + size m+--+-- In invariant 1, the types of the auxiliary functions are as follows+-- for reference:+--+-- > toListFTE   :: FingerTree (Elem a) -> [a]+-- > toListFTN   :: FingerTree (Node c) -> [c]+-- > toListThinN :: Thin (Node b) -> [b]+-- > toListD     :: Digit12 b -> [b]+liftA2Middle+  :: (b -> c)              -- ^ @ffirstx@+  -> (b -> c)              -- ^ @flastx@+  -> (a -> b -> c)         -- ^ @f@+  -> FingerTree (Elem a)   -- ^ @midxs@+  -> Rigid b               -- ^ @Rigid s pr m sf@ (@pr@: prefix, @sf@: suffix)+  -> FingerTree (Node c)  -- Not at the bottom yet -aptyMiddle firstf-           lastf-           map23-           fs-           (Rigid s pr (DeepTh sm prm mm sfm) sf)-    = Deep (sm + s * (size fs + 1)) -- note: sm = s - size pr - size sf-           (fmap (fmap firstf) (digit12ToDigit prm))-           (aptyMiddle (fmap firstf)-                       (fmap lastf)-                       (fmap . map23)-                       fs-                       (Rigid s (squashL pr prm) mm (squashR sfm sf)))-           (fmap (fmap lastf) (digit12ToDigit sfm))+liftA2Middle+    ffirstx+    flastx+    f+    midxs+    (Rigid s pr (DeepTh sm prm mm sfm) sf)+    -- note: size (DeepTh sm pr mm sfm) = sm = size pr + size mm + size sfm+    = Deep (sm + s * (size midxs + 1)) -- note: sm = s - size pr - size sf+           (fmap (fmap ffirstx) (digit12ToDigit prm))+           (liftA2Middle+               (fmap ffirstx)+               (fmap flastx)+               (fmap . f)+               midxs+               (Rigid s (squashL pr prm) mm (squashR sfm sf)))+           (fmap (fmap flastx) (digit12ToDigit sfm))  -- At the bottom -aptyMiddle firstf-           lastf-           map23-           fs-           (Rigid s pr EmptyTh sf)-     = deep-            (One (fmap firstf sf))-            (mapMulFT s (\(Elem f) -> fmap (fmap (map23 f)) converted) fs)-            (One (fmap lastf pr))+liftA2Middle+    ffirstx+    flastx+    f+    midxs+    (Rigid s pr EmptyTh sf)+    = deep+           (One (fmap ffirstx sf))+           (mapMulFT s (\(Elem x) -> fmap (fmap (f x)) converted) midxs)+           (One (fmap flastx pr))    where converted = node2 pr sf -aptyMiddle firstf-           lastf-           map23-           fs-           (Rigid s pr (SingleTh q) sf)-     = deep-            (Two (fmap firstf q) (fmap firstf sf))-            (mapMulFT s (\(Elem f) -> fmap (fmap (map23 f)) converted) fs)-            (Two (fmap lastf pr) (fmap lastf q))+liftA2Middle+    ffirstx+    flastx+    f+    midxs+    (Rigid s pr (SingleTh q) sf)+    = deep+           (Two (fmap ffirstx q) (fmap ffirstx sf))+           (mapMulFT s (\(Elem x) -> fmap (fmap (f x)) converted) midxs)+           (Two (fmap flastx pr) (fmap flastx q))    where converted = node3 pr q sf  digit12ToDigit :: Digit12 a -> Digit a@@ -721,7 +785,7 @@ -- @Node(Node(Elem y))@. The multiplier argument serves to make the annotations -- match up properly. mapMulFT :: Int -> (a -> b) -> FingerTree a -> FingerTree b-mapMulFT _ _ EmptyT = EmptyT+mapMulFT !_ _ EmptyT = EmptyT mapMulFT _mul f (Single a) = Single (f a) mapMulFT mul f (Deep s pr m sf) = Deep (mul * s) (fmap f pr) (mapMulFT mul (mapMulNode mul f) m) (fmap f sf) @@ -885,7 +949,11 @@  instance Monoid (Seq a) where     mempty = empty+#if MIN_VERSION_base(4,9,0)+    mappend = (Semigroup.<>)+#else     mappend = (><)+#endif  #if MIN_VERSION_base(4,9,0) -- | @since 0.5.7@@ -1375,6 +1443,240 @@     three = liftA3 Three m m m     deepA = liftA3 (Deep (n * mSize))     emptyTree = pure EmptyT++data RCountMid a = RCountMid+  !(Node a)  -- End of the first+  !Int -- Number of units in the middle+  !(Node a)  -- Beginning of the last++{-+We could generalize beforeSeq quite easily to++  beforeSeq :: (a -> c) -> Seq a -> Seq b -> Seq c++This would let us add a rewrite rule++  fmap f xs <* ys  ==>  beforeSeq f xs ys++We don't currently bother because I don't yet know of a practical use for (<*)+for sequences; a rewrite rule to optimize it seems like extreme overkill.+-}++beforeSeq :: Seq a -> Seq b -> Seq a+beforeSeq xs ys = replicateEach (length ys) xs++-- | Replicate each element of a sequence the given number of times.+--+-- @replicateEach 3 [1,2] = [1,1,1,2,2,2]@+-- @replicateEach n xs = xs >>= replicate n@+replicateEach :: Int -> Seq a -> Seq a+-- The main idea is that we construct a function that takes an element and+-- produces a 2-3 tree representing that element replicated lenys times. We map+-- that function over the sequence to (mostly) produce the desired fingertree. But+-- if we *just* did that, we'd end up with a fingertree of 2-3 trees of the given+-- size, not of elements. So we need to work our way down to the appropriate+-- level by building the left side of the fingertree corresponding to the first+-- 2-3 tree and the right side corresponding to the last one, along with the+-- 2-3 trees corresponding to the right side of the first and the left side of+-- the last.+replicateEach lenys xs = case viewl xs of+  EmptyL -> empty+  firstx :< xs' -> case viewr xs' of+    EmptyR -> replicate lenys firstx+    Seq midxs :> lastx -> case lenys of+      0 -> empty+      1 -> xs+      2 ->+        Seq $ rep2EachFT fxE midxs lxE+      3 ->+        Seq $ rep3EachFT fxE midxs lxE+      _ -> Seq $ case lenys `quotRem` 3 of  -- lenys > 3+             (q,0) -> Deep (lenys * length xs) fd3+               (repEachMiddle_ lift_elem (RCountMid fn3 (q - 2) ln3))+               ld3+                   where+                    lift_elem a = let n3a = n3 a in (n3a, n3a, n3a)+             (q,1) -> Deep (lenys * length xs) fd2+               (repEachMiddle_ lift_elem (RCountMid fn2 (q - 1) ln2))+               ld2+                   where+                    lift_elem a = let n2a = n2 a in (n2a, n3 a, n2a)+             (q,_) -> Deep (lenys * length xs) fd3+               (repEachMiddle_ lift_elem (RCountMid fn2 (q - 1) ln3))+               ld2+                   where+                    lift_elem a = let n3a = n3 a in (n3a, n3a, n2 a)+        where+          repEachMiddle_ = repEachMiddle midxs lenys 3 fn3 ln3+          fd2 = Two fxE fxE+          fd3 = Three fxE fxE fxE+          ld2 = Two lxE lxE+          ld3 = Three lxE lxE lxE+          fn2 = Node2 2 fxE fxE+          fn3 = Node3 3 fxE fxE fxE+          ln2 = Node2 2 lxE lxE+          ln3 = Node3 3 lxE lxE lxE+          n3 a = Node3 3 (Elem a) (Elem a) (Elem a)+          n2 a = Node2 2 (Elem a) (Elem a)+      where+          fxE = Elem firstx+          lxE = Elem lastx++rep2EachFT :: Elem a -> FingerTree (Elem a) -> Elem a -> FingerTree (Elem a)+rep2EachFT firstx xs lastx =+                 Deep (size xs * 2 + 4)+                      (Two firstx firstx)+                      (mapMulFT 2 (\ex -> Node2 2 ex ex) xs)+                      (Two lastx lastx)++rep3EachFT :: Elem a -> FingerTree (Elem a) -> Elem a -> FingerTree (Elem a)+rep3EachFT firstx xs lastx =+                 Deep (size xs * 3 + 6)+                      (Three firstx firstx firstx)+                      (mapMulFT 3 (\ex -> Node3 3 ex ex ex) xs)+                      (Three lastx lastx lastx)++-- Invariants for repEachMiddle:+--+-- 1. midxs is constant: the middle bit in the original sequence (xs = (first <: Seq midxs :> last))+-- 2. lenys is constant: the length of ys+-- 3. firstx and pr repeat the same element: the first one in the original sequence xs+-- 4. lastx  and sf repeat the same element: the last  one in the original sequence xs+-- 5. sizec = size firstx = size lastx+-- 6. lenys = deep_count * sizec + size pr + size pf+-- 7. let (lft, fill, rght) = fill23 x, for any x:+--      7a. All three sequences repeat the element x+--      7b. size fill = sizec+--      7c. size lft  = size sf+--      7d. size rght = size pr+-- 8. size result = deep_count * sizec + lenys * (size midxs + 1)+repEachMiddle+  :: FingerTree (Elem a)  -- midxs+  -> Int                  -- lenys+  -> Int                  -- sizec+  -> Node c               -- firstx+  -> Node c               -- lastx+  -> (a -> (Node c, Node c, Node c))  -- fill23+  -> RCountMid c          -- (RCountMid pr deep_count sf)+  -> FingerTree (Node c)  -- result++-- At the bottom++repEachMiddle midxs lenys+            !_sizec+            _firstx+            _lastx+            fill23+            (RCountMid pr 0 sf)+     = Deep (lenys * (size midxs + 1))+            (One pr)+            (mapMulFT lenys fill23_final midxs)+            (One sf)+   where+     -- fill23_final ::  Elem a -> Node (Node c)+     fill23_final (Elem a) = case fill23 a of+        -- See the note on lift_fill23 for an explanation of this+        -- lazy pattern.+        ~(lft, _fill, rght) -> Node2 (size pr + size sf) lft rght++repEachMiddle midxs lenys+            !sizec+            firstx+            lastx+            fill23+            (RCountMid pr 1 sf)+     = Deep (sizec + lenys * (size midxs + 1))+            (Two pr firstx)+            (mapMulFT lenys fill23_final midxs)+            (Two lastx sf)+   where+     -- fill23_final ::  Elem a -> Node (Node c)+     fill23_final (Elem a) = case fill23 a of+        -- See the note on lift_fill23 for an explanation of this+        -- lazy pattern.+        ~(lft, fill, rght) -> Node3 (size pr + size sf + sizec) lft fill rght++-- Not at the bottom yet++repEachMiddle midxs lenys+            !sizec+            firstx+            lastx+            fill23+            (RCountMid pr deep_count sf)  -- deep_count > 1+  = case deep_count `quotRem` 3 of+      (q,0)+       -> deep'+        (Two firstx firstx)+        (repEachMiddle_+           (lift_fill23 TOT3 TOT2 fill23)+           (RCountMid pr' (q - 1) sf'))+        (One lastx)+       where+        pr' = node2 firstx pr+        sf' = node3 lastx lastx sf+      (q,1)+       -> deep'+        (Two firstx firstx)+        (repEachMiddle_+           (lift_fill23 TOT3 TOT3 fill23)+           (RCountMid pr' (q - 1) sf'))+        (Two lastx lastx)+       where+        pr' = node3 firstx firstx pr+        sf' = node3 lastx lastx sf+      (q,_) -- the remainder is 2+       -> deep'+        (One firstx)+        (repEachMiddle_+           (lift_fill23 TOT2 TOT2 fill23)+           (RCountMid pr' q sf'))+        (One lastx)+       where+        pr' = node2 firstx pr+        sf' = node2 lastx sf++  where+    deep' = Deep (deep_count * sizec + lenys * (size midxs + 1))+    repEachMiddle_ = repEachMiddle midxs lenys sizec' fn3 ln3+    sizec' = 3 * sizec+    fn3 = Node3 sizec' firstx firstx firstx+    ln3 = Node3 sizec' lastx lastx lastx+    spr = size pr+    ssf = size sf+    lift_fill23+      :: TwoOrThree+      -> TwoOrThree+      -> (a -> (b, b, b))+      -> a -> (Node b, Node b, Node b)+    lift_fill23 !tl !tr f a = (lft', fill', rght')+      where+        -- We use a strict pattern match on the recursive call.  This means+        -- that we build the 2-3 trees from the *bottom up* instead of from the+        -- *top down*. We do it this way for two reasons:+        --+        -- 1. The trees are never very deep, so we don't get much locality+        -- benefit from building them lazily.+        --+        -- 2. Building the trees lazily would require us to build four thunks+        -- at each level of each tree, which seems just a bit pricy.+        --+        -- Does this break the incremental optimality? I don't believe it does.+        -- As far as I can tell, each sequence operation that inspects one of+        -- these trees either inspects only its root (to get its size for+        -- indexing purposes) or descends all the way to the bottom. So we're+        -- strict here, and lazy in the construction of+        -- the root in fill23_final.+        !(lft, fill, rght) = f a+        !fill' = Node3 (3 * sizec) fill fill fill+        !lft' = case tl of+          TOT2 -> Node2 (ssf + sizec) lft fill+          TOT3 -> Node3 (ssf + 2 * sizec) lft fill fill+        !rght' = case tr of+          TOT2 -> Node2 (spr + sizec) rght fill+          TOT3 -> Node3 (spr + 2 * sizec) rght fill fill++data TwoOrThree = TOT2 | TOT3  ------------------------------------------------------------------------ -- Construction
src/Data/Sequence/Internal/Sorting.hs view
@@ -394,7 +394,6 @@     pr' = foldDigit (<+>) f pr     sf' = foldDigit (<+>) f sf     m' = foldToMaybeTree (<+>) (foldNode (<+>) f) m-{-# INLINE foldToMaybeTree #-}  -- | A 'Data.Sequence.foldMapWithIndex'-like function, specialized to the -- 'Data.Semigroup.Option' monoid, which takes advantage of the
src/Data/Set.hs view
@@ -88,6 +88,10 @@             -- * Deletion             , delete +            -- * Generalized insertion/deletion++            , alterF+             -- * Query             , member             , notMember
src/Data/Set/Internal.hs view
@@ -148,6 +148,7 @@             , singleton             , insert             , delete+            , alterF             , powerSet              -- * Combine@@ -230,6 +231,7 @@             ) where  import Prelude hiding (filter,foldl,foldr,null,map,take,drop,splitAt)+import Control.Applicative (Const(..)) import qualified Data.List as List import Data.Bits (shiftL, shiftR) #if !MIN_VERSION_base(4,8,0)@@ -245,6 +247,9 @@ import Data.Semigroup (stimesIdempotentMonoid) import Data.Functor.Classes #endif+#if MIN_VERSION_base(4,8,0)+import Data.Functor.Identity (Identity)+#endif import qualified Data.Foldable as Foldable #if !MIN_VERSION_base(4,8,0) import Data.Foldable (Foldable (foldMap))@@ -592,6 +597,72 @@ {-# INLINABLE delete #-} #else {-# INLINE delete #-}+#endif++-- | /O(log n)/ @('alterF' f x s)@ can delete or insert @x@ in @s@ depending on+-- whether an equal element is found in @s@.+--+-- In short:+--+-- @+-- 'member' x \<$\> 'alterF' f x s = f ('member' x s)+-- @+--+-- Note that unlike 'insert', 'alterF' will /not/ replace an element equal to+-- the given value.+--+-- Note: 'alterF' is a variant of the @at@ combinator from "Control.Lens.At".+--+-- @since 0.6.3.1+alterF :: (Ord a, Functor f) => (Bool -> f Bool) -> a -> Set a -> f (Set a)+alterF f k s = fmap choose (f member_)+  where+    (member_, inserted, deleted) = case alteredSet k s of+        Deleted d           -> (True , s, d)+        Inserted i          -> (False, i, s)++    choose True  = inserted+    choose False = deleted+#ifndef __GLASGOW_HASKELL__+{-# INLINE alterF #-}+#else+{-# INLINABLE [2] alterF #-}++{-# RULES+"alterF/Const" forall k (f :: Bool -> Const a Bool) . alterF f k = \s -> Const . getConst . f $ member k s+ #-}+#endif++#if MIN_VERSION_base(4,8,0)+{-# SPECIALIZE alterF :: Ord a => (Bool -> Identity Bool) -> a -> Set a -> Identity (Set a) #-}+#endif++data AlteredSet a+      -- | The needle is present in the original set.+      -- We return the set where the needle is deleted.+    = Deleted !(Set a)++      -- | The needle is not present in the original set.+      -- We return the set with the needle inserted.+    | Inserted !(Set a)++alteredSet :: Ord a => a -> Set a -> AlteredSet a+alteredSet x0 s0 = go x0 s0+  where+    go :: Ord a => a -> Set a -> AlteredSet a+    go x Tip           = Inserted (singleton x)+    go x (Bin _ y l r) = case compare x y of+        LT -> case go x l of+            Deleted d           -> Deleted (balanceR y d r)+            Inserted i          -> Inserted (balanceL y i r)+        GT -> case go x r of+            Deleted d           -> Deleted (balanceL y l d)+            Inserted i          -> Inserted (balanceR y l i)+        EQ -> Deleted (glue l r)+#if __GLASGOW_HASKELL__+{-# INLINABLE alteredSet #-}+#else+{-# INLINE alteredSet #-} #endif  {--------------------------------------------------------------------
src/Data/Tree.hs view
@@ -93,7 +93,7 @@ -- | Non-empty, possibly infinite, multi-way trees; also known as /rose trees/. data Tree a = Node {         rootLabel :: a,         -- ^ label value-        subForest :: Forest a   -- ^ zero or more child trees+        subForest :: [Tree a]   -- ^ zero or more child trees     } #ifdef __GLASGOW_HASKELL__   deriving ( Eq@@ -107,6 +107,8 @@   deriving (Eq, Read, Show) #endif +-- | This type synonym exists primarily for historical+-- reasons. type Forest a = [Tree a]  #if MIN_VERSION_base(4,9,0)@@ -249,7 +251,7 @@ -- `- 20 -- @ ---drawForest :: Forest String -> String+drawForest :: [Tree String] -> String drawForest  = unlines . map drawTree  draw :: Tree String -> [String]@@ -321,7 +323,7 @@ -- -- Find depth of the tree; i.e. the number of branches from the root of the tree to the furthest leaf: ----- > foldTree (\_ xs -> if null xs then 0 else 1 + maximum xs) (Node 1 [Node 2[], Node 3 []]) == 1+-- > foldTree (\_ xs -> if null xs then 0 else 1 + maximum xs) (Node 1 [Node 2 [], Node 3 []]) == 1 -- -- You can even implement traverse using foldTree: --@@ -377,7 +379,7 @@ -- -- For a monadic version see 'unfoldForestM_BF'. ---unfoldForest :: (b -> (a, [b])) -> [b] -> Forest a+unfoldForest :: (b -> (a, [b])) -> [b] -> [Tree a] unfoldForest f = map (unfoldTree f)  -- | Monadic tree builder, in depth-first order.@@ -388,7 +390,7 @@     return (Node a ts)  -- | Monadic forest builder, in depth-first order-unfoldForestM :: Monad m => (b -> m (a, [b])) -> [b] -> m (Forest a)+unfoldForestM :: Monad m => (b -> m (a, [b])) -> [b] -> m ([Tree a]) unfoldForestM f = Prelude.mapM (unfoldTreeM f)  -- | Monadic tree builder, in breadth-first order.@@ -410,7 +412,7 @@ -- -- Implemented using an algorithm adapted from /Breadth-First Numbering: Lessons -- from a Small Exercise in Algorithm Design/, by Chris Okasaki, /ICFP'00/.-unfoldForestM_BF :: Monad m => (b -> m (a, [b])) -> [b] -> m (Forest a)+unfoldForestM_BF :: Monad m => (b -> m (a, [b])) -> [b] -> m ([Tree a]) unfoldForestM_BF f = liftM toList . unfoldForestQ f . fromList  -- Takes a sequence (queue) of seeds and produces a sequence (reversed queue) of