Skip to content

Commit e661937

Browse files
authored
Add 'compose' for maps (#672)
Add 'compose' for maps
1 parent 70834f2 commit e661937

File tree

10 files changed

+110
-1
lines changed

10 files changed

+110
-1
lines changed

containers-tests/tests/intmap-properties.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Data.IntMap.Internal.Debug (showTree)
1313
import IntMapValidity (valid)
1414

1515
import Control.Applicative (Applicative(..))
16+
import Control.Monad ((<=<))
1617
import Data.Monoid
1718
import Data.Maybe hiding (mapMaybe)
1819
import qualified Data.Maybe as Maybe (mapMaybe)
@@ -174,6 +175,7 @@ main = defaultMain
174175
, testProperty "lookupLE" prop_lookupLE
175176
, testProperty "lookupGE" prop_lookupGE
176177
, testProperty "disjoint" prop_disjoint
178+
, testProperty "compose" prop_compose
177179
, testProperty "lookupMin" prop_lookupMin
178180
, testProperty "lookupMax" prop_lookupMax
179181
, testProperty "findMin" prop_findMin
@@ -1243,6 +1245,9 @@ prop_intersectionWithKeyModel xs ys
12431245
prop_disjoint :: UMap -> UMap -> Property
12441246
prop_disjoint m1 m2 = disjoint m1 m2 === null (intersection m1 m2)
12451247

1248+
prop_compose :: IMap -> IMap -> Int -> Property
1249+
prop_compose bc ab k = (compose bc ab !? k) === ((bc !?) <=< (ab !?)) k
1250+
12461251
-- TODO: the second argument should be simply an 'IntSet', but that
12471252
-- runs afoul of our orphan instance.
12481253
prop_restrictKeys :: IMap -> IMap -> Property

containers-tests/tests/map-properties.hs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Data.Map.Internal.Debug (showTree, showTreeWith, balanced)
1313
import Control.Applicative (Const(Const, getConst), pure, (<$>), (<*>))
1414
import Control.Monad.Trans.State.Strict
1515
import Control.Monad.Trans.Class
16-
import Control.Monad (liftM4)
16+
import Control.Monad (liftM4, (<=<))
1717
import Data.Functor.Identity (Identity(Identity, runIdentity))
1818
import Data.Monoid
1919
import Data.Maybe hiding (mapMaybe)
@@ -180,6 +180,7 @@ main = defaultMain
180180
, testProperty "intersectionWithKey" prop_intersectionWithKey
181181
, testProperty "intersectionWithKeyModel" prop_intersectionWithKeyModel
182182
, testProperty "disjoint" prop_disjoint
183+
, testProperty "compose" prop_compose
183184
, testProperty "differenceMerge" prop_differenceMerge
184185
, testProperty "unionWithKeyMerge" prop_unionWithKeyMerge
185186
, testProperty "mergeWithKey model" prop_mergeWithKeyModel
@@ -1160,6 +1161,9 @@ prop_intersectionWithKeyModel xs ys
11601161
prop_disjoint :: UMap -> UMap -> Property
11611162
prop_disjoint m1 m2 = disjoint m1 m2 === null (intersection m1 m2)
11621163

1164+
prop_compose :: IMap -> IMap -> Int -> Property
1165+
prop_compose bc ab k = (compose bc ab !? k) === ((bc !?) <=< (ab !?)) k
1166+
11631167
prop_mergeWithKeyModel :: [(Int,Int)] -> [(Int,Int)] -> Bool
11641168
prop_mergeWithKeyModel xs ys
11651169
= and [ testMergeWithKey f keep_x keep_y

containers/src/Data/IntMap/Internal.hs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ module Data.IntMap.Internal (
131131
, intersectionWith
132132
, intersectionWithKey
133133

134+
-- ** Compose
135+
, compose
136+
134137
-- ** General combining function
135138
, SimpleWhenMissing
136139
, SimpleWhenMatched
@@ -765,6 +768,25 @@ disjoint t1@(Bin p1 m1 l1 r1) t2@(Bin p2 m2 l2 r2)
765768
| zero p1 m2 = disjoint t1 l2
766769
| otherwise = disjoint t1 r2
767770

771+
{--------------------------------------------------------------------
772+
Compose
773+
--------------------------------------------------------------------}
774+
-- | /O(|ab|*min(|bc|,W))/. Relate the keys of one map to the values of
775+
-- the other, by using the values of the former as keys for lookups
776+
-- in the latter.
777+
--
778+
-- > compose (fromList [('a', "A"), ('b', "B")]) (fromList [(1,'a'),(2,'b'),(3,'z')]) = fromList [(1,"A"),(2,"B")]
779+
--
780+
-- @
781+
-- ('compose' bc ab '!?') = (bc '!?') <=< (ab '!?')
782+
-- @
783+
--
784+
-- @since UNRELEASED
785+
compose :: IntMap c -> IntMap Int -> IntMap c
786+
compose bc !ab
787+
| null bc = empty
788+
| otherwise = mapMaybe (bc !?) ab
789+
768790
{--------------------------------------------------------------------
769791
Construction
770792
--------------------------------------------------------------------}

containers/src/Data/IntMap/Lazy.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ module Data.IntMap.Lazy (
146146
-- ** Disjoint
147147
, disjoint
148148

149+
-- ** Compose
150+
, compose
151+
149152
-- ** Universal combining function
150153
, mergeWithKey
151154

containers/src/Data/IntMap/Strict.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ module Data.IntMap.Strict (
165165
-- ** Disjoint
166166
, disjoint
167167

168+
-- ** Compose
169+
, compose
170+
168171
-- ** Universal combining function
169172
, mergeWithKey
170173

containers/src/Data/IntMap/Strict/Internal.hs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ module Data.IntMap.Strict.Internal (
163163
-- ** Disjoint
164164
, disjoint
165165

166+
-- ** Compose
167+
, compose
168+
166169
-- ** Universal combining function
167170
, mergeWithKey
168171

@@ -715,6 +718,25 @@ intersectionWithKey :: (Key -> a -> b -> c) -> IntMap a -> IntMap b -> IntMap c
715718
intersectionWithKey f m1 m2
716719
= mergeWithKey' bin (\(Tip k1 x1) (Tip _k2 x2) -> Tip k1 $! f k1 x1 x2) (const Nil) (const Nil) m1 m2
717720

721+
{--------------------------------------------------------------------
722+
Compose
723+
--------------------------------------------------------------------}
724+
-- | /O(|ab|*min(|bc|,W))/. Relate the keys of one map to the values of
725+
-- the other, by using the values of the former as keys for lookups
726+
-- in the latter.
727+
--
728+
-- > compose (fromList [('a', "A"), ('b', "B")]) (fromList [(1,'a'),(2,'b'),(3,'z')]) = fromList [(1,"A"),(2,"B")]
729+
--
730+
-- @
731+
-- ('compose' bc ab '!?') = (bc '!?') <=< (ab '!?')
732+
-- @
733+
--
734+
-- @since UNRELEASED
735+
compose :: IntMap c -> IntMap Int -> IntMap c
736+
compose bc !ab
737+
| null bc = empty
738+
| otherwise = mapMaybe (bc !?) ab
739+
718740
{--------------------------------------------------------------------
719741
MergeWithKey
720742
--------------------------------------------------------------------}

containers/src/Data/Map/Internal.hs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ module Data.Map.Internal (
192192
-- ** Disjoint
193193
, disjoint
194194

195+
-- ** Compose
196+
, compose
197+
195198
-- ** General combining function
196199
, SimpleWhenMissing
197200
, SimpleWhenMatched
@@ -2088,6 +2091,25 @@ disjoint (Bin _ k _ l r) t
20882091
where
20892092
(lt,found,gt) = splitMember k t
20902093

2094+
{--------------------------------------------------------------------
2095+
Compose
2096+
--------------------------------------------------------------------}
2097+
-- | /O(|ab|*log(|bc|))/. Relate the keys of one map to the values of
2098+
-- the other, by using the values of the former as keys for lookups
2099+
-- in the latter.
2100+
--
2101+
-- > compose (fromList [('a', "A"), ('b', "B")]) (fromList [(1,'a'),(2,'b'),(3,'z')]) = fromList [(1,"A"),(2,"B")]
2102+
--
2103+
-- @
2104+
-- ('compose' bc ab '!?') = (bc '!?') <=< (ab '!?')
2105+
-- @
2106+
--
2107+
-- @since UNRELEASED
2108+
compose :: Ord b => Map b c -> Map a b -> Map a c
2109+
compose bc !ab
2110+
| null bc = empty
2111+
| otherwise = mapMaybe (bc !?) ab
2112+
20912113
#if !MIN_VERSION_base (4,8,0)
20922114
-- | The identity type.
20932115
newtype Identity a = Identity { runIdentity :: a }

containers/src/Data/Map/Lazy.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ module Data.Map.Lazy (
166166
-- ** Disjoint
167167
, disjoint
168168

169+
-- ** Compose
170+
, compose
171+
169172
-- ** General combining functions
170173
-- | See "Data.Map.Merge.Lazy"
171174

containers/src/Data/Map/Strict.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ module Data.Map.Strict
182182
-- ** Disjoint
183183
, disjoint
184184

185+
-- ** Compose
186+
, compose
187+
185188
-- ** General combining functions
186189
-- | See "Data.Map.Merge.Strict"
187190

containers/src/Data/Map/Strict/Internal.hs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ module Data.Map.Strict.Internal
145145
-- ** Disjoint
146146
, disjoint
147147

148+
-- ** Compose
149+
, compose
150+
148151
-- ** General combining function
149152
, SimpleWhenMissing
150153
, SimpleWhenMatched
@@ -1200,6 +1203,25 @@ forceMaybe Nothing = Nothing
12001203
forceMaybe m@(Just !_) = m
12011204
{-# INLINE forceMaybe #-}
12021205

1206+
{--------------------------------------------------------------------
1207+
Compose
1208+
--------------------------------------------------------------------}
1209+
-- | /O(|ab|*log(|bc|))/. Relate the keys of one map to the values of
1210+
-- the other, by using the values of the former as keys for lookups
1211+
-- in the latter.
1212+
--
1213+
-- > compose (fromList [('a', "A"), ('b', "B")]) (fromList [(1,'a'),(2,'b'),(3,'z')]) = fromList [(1,"A"),(2,"B")]
1214+
--
1215+
-- @
1216+
-- ('compose' bc ab '!?') = (bc '!?') <=< (ab '!?')
1217+
-- @
1218+
--
1219+
-- @since UNRELEASED
1220+
compose :: Ord b => Map b c -> Map a b -> Map a c
1221+
compose bc !ab
1222+
| null bc = empty
1223+
| otherwise = mapMaybe (bc !?) ab
1224+
12031225
{--------------------------------------------------------------------
12041226
MergeWithKey
12051227
--------------------------------------------------------------------}

0 commit comments

Comments
 (0)