{-# LANGUAGE NoBangPatterns, CPP, DeriveDataTypeable, ScopedTypeVariables #-} ----------------------------------------------------------------------------- -- | -- Module : Data.CompactMap -- Copyright : (c) David Himmelstrup 2008 -- License : BSD-style -- Maintainer : libraries@haskell.org -- Stability : experimental -- Portability : portable -- -- An efficient implementation of maps from keys to values (dictionaries). -- -- Since many function names (but not the type name) clash with -- "Prelude" names, this module is usually imported @qualified@, e.g. -- -- > import Data.CompactMap (Map) -- > import qualified Data.CompactMap as Map -- -- The implementation of 'Map' is based on /size balanced/ binary trees (or -- trees of /bounded balance/) as described by: -- -- * Stephen Adams, \"/Efficient sets: a balancing act/\", -- Journal of Functional Programming 3(4):553-562, October 1993, -- . -- -- * J. Nievergelt and E.M. Reingold, -- \"/Binary search trees of bounded balance/\", -- SIAM journal of computing 2(1), March 1973. -- -- Note that the implementation is /left-biased/ -- the elements of a -- first argument are always preferred to the second, for example in -- 'union' or 'insert'. -- -- Operation comments contain the operation time complexity in -- the Big-O notation . ----------------------------------------------------------------------------- module Data.CompactMap ( -- * Map type Map -- instance Eq,Show,Read -- * Operators , (!) --, (\\) -- * Query , null , size , member , notMember , lookup , findWithDefault -- * Construction , empty , singleton -- ** Insertion , insert , insertWith, insertWithKey, insertLookupWithKey -- ** Delete\/Update , delete , adjust , adjustWithKey , update , updateWithKey , updateLookupWithKey , alter -- * Combine , union , unionWith , unionWithKey , unions , unionsWith{- -- ** Difference , difference , differenceWith , differenceWithKey -- ** Intersection , intersection , intersectionWith , intersectionWithKey-} -- * Traversal -- ** Map , map , mapWithKey{- , mapAccum , mapAccumWithKey-} , mapKeys , mapKeysWith , mapKeysMonotonic -- ** Fold , fold , foldWithKey -- * Conversion , elems , keys , keysSet , assocs -- ** Lists , toList , fromList , fromListWith , fromListWithKey -- ** Ordered lists , toAscList , fromAscList , fromAscListWith , fromAscListWithKey , fromDistinctAscList -- * Filter , filter , filterWithKey , partition , partitionWithKey , mapMaybe , mapMaybeWithKey , mapEither , mapEitherWithKey{- , split , splitLookup -- * Submap , isSubmapOf, isSubmapOfBy , isProperSubmapOf, isProperSubmapOfBy -- * Indexed , lookupIndex , findIndex , elemAt , updateAt , deleteAt-} -- * Min\/Max , findMin , findMax , deleteMin -- , deleteMax , deleteFindMin -- , deleteFindMax {- , updateMin , updateMax , updateMinWithKey , updateMaxWithKey , minView , maxView , minViewWithKey , maxViewWithKey -- * Debugging , showTree , showTreeWith , valid-} ) where import Data.Monoid (Monoid(..)) import Control.Concurrent import Data.IORef import Data.Binary import Data.Typeable import Data.List (foldl') import System.IO.Unsafe import qualified Data.Maybe as Maybe import Data.Maybe (isJust) import Foreign (nullPtr) import Text.Read hiding (get) import Control.Monad import qualified Data.CompactMap.Index as Index import Data.CompactMap.Types as Types import qualified Data.Array.IArray as IArray import qualified Data.Set as Set import qualified Data.ByteString as Strict import qualified Data.ByteString.Lazy as Lazy import Prelude hiding (null,lookup,map,filter) import qualified Prelude import System.Mem.Weak data Range = Range Int Int -- | A Map from keys @k@ to values @a@. data Map k a = Empty | Existing { index :: !(MVar Index) , uniq :: {-# UNPACK #-} !(IORef Int) , range :: ![Range] , mapSize :: {-# UNPACK #-} !Int } #if !defined(HPC) deriving (Typeable) #endif {-------------------------------------------------------------------- Instances --------------------------------------------------------------------} instance (Eq k, Eq a, Binary k, Binary a) => Eq (Map k a) where m1 == m2 = toList m1 == toList m2 instance (Ord k, Ord a, Binary k, Binary a) => Ord (Map k a) where m1 `compare` m2 = toList m1 `compare` toList m2 instance (Binary k, Binary a, Show k, Show a) => Show (Map k a) where showsPrec d m = showParen (d > 10) $ showString "fromList " . shows (toList m) instance (Ord k, Binary k, Binary a, Read k, Read a) => Read (Map k a) where #ifdef __GLASGOW_HASKELL__ readPrec = parens $ prec 10 $ do Ident "fromList" <- lexP xs <- readPrec return (fromList xs) readListPrec = readListPrecDefault #else readsPrec p = readParen (p > 10) $ \ r -> do ("fromList",s) <- lex r (xs,t) <- reads s return (fromList xs,t) #endif instance Binary (Map k a) where put Empty = put (0::Int) put Existing{index=index,range=range,mapSize=mapSize} = let a = unsafePerformIO $ withMVar index $ Index.listKeyPointers in do put mapSize forM_ (IArray.elems a) $ \ptr -> do let ls = unsafePerformIO $ Index.getDataFromPointer ptr case findValue range ls of Nothing -> return () Just val -> do let key = unsafePerformIO $ Index.getKeyFromPointer ptr put (key,val) unsafePerformIO $ do withMVar index Index.touchIndex return $ return () get = do n <- get ls <- replicateM n get unsafePerformIO $ do idx <- Index.newIndex forM_ ls $ \(k,v) -> do keyCursor <- Index.newKeyCursor (indexBuffer idx) (Lazy.fromChunks [k]) Index.insertLargestKeyCursor idx keyCursor dataCursor <- Index.newDataCursor (indexBuffer idx) 0 (Just (Lazy.fromChunks [v])) Index.pushNewDataCursor keyCursor dataCursor --Index.insertBS idx (decodeStrict k :: k) 0 (Just (Lazy.fromChunks [v])) uniq <- newIORef 1 index <- newMVar idx return $ return $ Existing{index=index,uniq=uniq,range=addToRange 0 [],mapSize=n} instance (Ord k, Binary k, Binary a) => Monoid (Map k a) where mempty = empty mappend = union mconcat = unions {-------------------------------------------------------------------- Methods --------------------------------------------------------------------} infixl 9 ! -- ,\\ -- | /O(log n)/. Find the value at a key. -- Calls 'error' when the element can not be found. -- -- > fromList [(5,'a'), (3,'b')] ! 1 Error: element not in the map -- > fromList [(5,'a'), (3,'b')] ! 5 == 'a' (!) :: (Ord k, Binary k, Binary a) => Map k a -> k -> a m ! k = case lookup k m of Nothing -> error "element not in the map" Just x -> x -- | /O(1)/. Is the map empty? -- -- > Data.Map.null (empty) == True -- > Data.Map.null (singleton 1 'a') == False null :: Map k a -> Bool null m = size m == 0 -- | /O(1)/. The number of elements in the map. -- -- > size empty == 0 -- > size (singleton 1 'a') == 1 -- > size (fromList([(1,'a'), (2,'c'), (3,'b')])) == 3 size :: Map k a -> Int size Empty = 0 size Existing{mapSize=size} = size -- | /O(log n)/. Is the key a member of the map? See also 'notMember'. -- -- > member 5 (fromList [(5,'a'), (3,'b')]) == True -- > member 1 (fromList [(5,'a'), (3,'b')]) == False member :: (Ord k, Binary k) => k -> Map k a -> Bool member k Empty = False member k Existing{index=index,range=range} = unsafePerformIO $ withMVar index $ \idx -> do ls <- Index.lookupList idx k return $ isJust $ findValue range ls -- | /O(log n)/. Is the key not a member of the map? See also 'member'. -- -- > notMember 5 (fromList [(5,'a'), (3,'b')]) == False -- > notMember 1 (fromList [(5,'a'), (3,'b')]) == True notMember :: (Ord k, Binary k) => k -> Map k a -> Bool notMember k m = not (member k m) -- | /O(log n)/. Lookup the value at a key in the map. -- -- The function will return the corresponding value as @('Just' value)@, -- or 'Nothing' if the key isn't in the map. -- -- An example of using @lookup@: -- -- > import Prelude hiding (lookup) -- > import Data.CompactMap -- > -- > employeeDept = fromList([("John","Sales"), ("Bob","IT")]) -- > deptCountry = fromList([("IT","USA"), ("Sales","France")]) -- > countryCurrency = fromList([("USA", "Dollar"), ("France", "Euro")]) -- > -- > employeeCurrency :: String -> Maybe String -- > employeeCurrency name = do -- > dept <- lookup name employeeDept -- > country <- lookup dept deptCountry -- > lookup country countryCurrency -- > -- > main = do -- > putStrLn $ "John's currency: " ++ (show (employeeCurrency "John")) -- > putStrLn $ "Pete's currency: " ++ (show (employeeCurrency "Pete")) -- -- The output of this program: -- -- > John's currency: Just "Euro" -- > Pete's currency: Nothing lookup :: (Ord k, Binary k, Binary a) => k -> Map k a -> Maybe a lookup k Empty = Nothing lookup k Existing{index=index,range=range} = unsafePerformIO $ withMVar index $ \idx -> do ls <- Index.lookupList idx k case findValue range ls of Nothing -> return Nothing Just bs -> do mkWeak bs index Nothing return $ Just (decodeStrict bs) -- | /O(log n)/. The expression @('findWithDefault' def k map)@ returns -- the value at key @k@ or returns default value @def@ -- when the key is not in the map. -- -- > findWithDefault 'x' 1 (fromList [(5,'a'), (3,'b')]) == 'x' -- > findWithDefault 'x' 5 (fromList [(5,'a'), (3,'b')]) == 'a' findWithDefault :: (Ord k, Binary k, Binary a) => a -> k -> Map k a -> a findWithDefault def k m = case lookup k m of Nothing -> def Just x -> x -- | /O(1)/. The empty map. -- -- > empty == fromList [] -- > size empty == 0 empty :: Map k a empty = Empty -- | /O(1)/. A map with a single element. -- -- > singleton 1 'a' == fromList [(1, 'a')] -- > size (singleton 1 'a') == 1 singleton :: (Ord k, Binary k, Binary a) => k -> a -> Map k a singleton k a = insert k a empty -- | /O(log n)/. Insert a new key and value in the map. -- If the key is already present in the map, the associated value is -- replaced with the supplied value. 'insert' is equivalent to -- @'insertWith' 'const'@. -- -- > insert 5 'x' (fromList [(5,'a'), (3,'b')]) == fromList [(3, 'b'), (5, 'x')] -- > insert 7 'x' (fromList [(5,'a'), (3,'b')]) == fromList [(3, 'b'), (5, 'a'), (7, 'x')] -- > insert 5 'x' empty == singleton 5 'x' insert :: (Ord k, Binary k, Binary a) => k -> a -> Map k a -> Map k a insert k a m = unsafePerformIO $ withExisting m $ \Existing{index=index,uniq=uniq,range=range,mapSize=mapSize} -> withMVar index $ \idx -> do u <- readIORef uniq modifyIORef uniq succ ls <- Index.insert idx k u (Just a) let newSize | haveOldValue range ls = mapSize | otherwise = mapSize+1 return Existing{index=index,uniq=uniq,range=addToRange u range,mapSize=newSize} -- | /O(log n)/. Insert with a function, combining new value and old value. -- @'insertWith' f key value mp@ -- will insert the pair (key, value) into @mp@ if key does -- not exist in the map. If the key does exist, the function will -- insert the pair @(key, f new_value old_value)@. -- -- > insertWith (++) 5 "xxx" (fromList [(5,"a"), (3,"b")]) == fromList [(3, "b"), (5, "xxxa")] -- > insertWith (++) 7 "xxx" (fromList [(5,"a"), (3,"b")]) == fromList [(3, "b"), (5, "a"), (7, "xxx")] -- > insertWith (++) 5 "xxx" empty == singleton 5 "xxx" insertWith :: (Ord k, Binary k, Binary a) => (a -> a -> a) -> k -> a -> Map k a -> Map k a insertWith f k x m = insertWithKey (\_ x' y' -> f x' y') k x m -- | /O(log n)/. Insert with a function, combining key, new value and old value. -- @'insertWithKey' f key value mp@ -- will insert the pair (key, value) into @mp@ if key does -- not exist in the map. If the key does exist, the function will -- insert the pair @(key,f key new_value old_value)@. -- Note that the key passed to f is the same key passed to 'insertWithKey'. -- -- > let f key new_value old_value = (show key) ++ ":" ++ new_value ++ "|" ++ old_value -- > insertWithKey f 5 "xxx" (fromList [(5,"a"), (3,"b")]) == fromList [(3, "b"), (5, "5:xxx|a")] -- > insertWithKey f 7 "xxx" (fromList [(5,"a"), (3,"b")]) == fromList [(3, "b"), (5, "a"), (7, "xxx")] -- > insertWithKey f 5 "xxx" empty == singleton 5 "xxx" insertWithKey :: (Ord k, Binary k, Binary a) => (k -> a -> a -> a) -> k -> a -> Map k a -> Map k a insertWithKey f kx x Empty = singleton kx x insertWithKey f kx x Existing{index=index,uniq=uniq,range=range,mapSize=mapSize} = unsafePerformIO $ withMVar index $ \idx -> do u <- readIORef uniq modifyIORef uniq succ keyCursor <- Index.insertKey idx kx ls <- Index.getDataFromPointer keyCursor let oldVal = findValue range ls newVal = case oldVal of Nothing -> x Just old -> f kx x (decodeStrict old) newSize = if isJust oldVal then mapSize else mapSize + 1 dataCursor <- Index.newDataCursor (indexBuffer idx) u (Just $ encode newVal) Index.pushNewDataCursor keyCursor dataCursor return $ Existing{index=index,uniq=uniq,range=addToRange u range,mapSize=newSize} -- | /O(log n)/. Combines insert operation with old value retrieval. -- The expression (@'insertLookupWithKey' f k x map@) -- is a pair where the first element is equal to (@'lookup' k map@) -- and the second element equal to (@'insertWithKey' f k x map@). -- -- > let f key new_value old_value = (show key) ++ ":" ++ new_value ++ "|" ++ old_value -- > insertLookupWithKey f 5 "xxx" (fromList [(5,"a"), (3,"b")]) == (Just "a", fromList [(3, "b"), (5, "5:xxx|a")]) -- > insertLookupWithKey f 7 "xxx" (fromList [(5,"a"), (3,"b")]) == (Nothing, fromList [(3, "b"), (5, "a"), (7, "xxx")]) -- > insertLookupWithKey f 5 "xxx" empty == (Nothing, singleton 5 "xxx") -- -- This is how to define @insertLookup@ using @insertLookupWithKey@: -- -- > let insertLookup kx x t = insertLookupWithKey (\_ a _ -> a) kx x t -- > insertLookup 5 "x" (fromList [(5,"a"), (3,"b")]) == (Just "a", fromList [(3, "b"), (5, "x")]) -- > insertLookup 7 "x" (fromList [(5,"a"), (3,"b")]) == (Nothing, fromList [(3, "b"), (5, "a"), (7, "x")]) insertLookupWithKey :: (Ord k, Binary k, Binary a) => (k -> a -> a -> a) -> k -> a -> Map k a -> (Maybe a,Map k a) insertLookupWithKey f k a Empty = (Nothing, singleton k a) insertLookupWithKey f k a Existing{index=index,uniq=uniq,range=range,mapSize=mapSize} = unsafePerformIO $ withMVar index $ \idx -> do u <- readIORef uniq modifyIORef uniq succ keyCursor <- Index.insertKey idx k ls <- Index.getDataFromPointer keyCursor let oldValBS = findValue range ls oldVal = fmap decodeStrict oldValBS newVal = case oldVal of Nothing -> a Just old -> f k a old newSize = if isJust oldVal then mapSize else mapSize + 1 case oldValBS of Just val -> mkWeak val index Nothing>>return(); Nothing -> return () dataCursor <- Index.newDataCursor (indexBuffer idx) u (Just $ encode newVal) Index.pushNewDataCursor keyCursor dataCursor return $ (oldVal, Existing{index=index,uniq=uniq,range=addToRange u range,mapSize=newSize}) -- | /O(log n)/. Delete a key and its value from the map. When the key is not -- a member of the map, the original map is returned. -- -- > delete 5 (fromList [(5,"a"), (3,"b")]) == singleton 3 "b" -- > delete 7 (fromList [(5,"a"), (3,"b")]) == fromList [(3, "b"), (5, "a")] -- > delete 5 empty == empty delete :: (Ord k, Binary k) => k -> Map k a -> Map k a delete k Empty = Empty delete k Existing{index=index,uniq=uniq,range=range,mapSize=mapSize} = unsafePerformIO $ withMVar index $ \idx -> do u <- readIORef uniq modifyIORef uniq succ ls <- Index.insert idx k u (Nothing :: Maybe ()) let newSize | haveOldValue range ls = mapSize-1 | otherwise = mapSize return Existing{index=index,uniq=uniq,range=addToRange u range,mapSize=newSize} -- | /O(log n)/. Update a value at a specific key with the result of the provided function. -- When the key is not -- a member of the map, the original map is returned. -- -- > adjust ("new " ++) 5 (fromList [(5,"a"), (3,"b")]) == fromList [(3, "b"), (5, "new a")] -- > adjust ("new " ++) 7 (fromList [(5,"a"), (3,"b")]) == fromList [(3, "b"), (5, "a")] -- > adjust ("new " ++) 7 empty == empty adjust :: (Ord k, Binary k, Binary a) => (a -> a) -> k -> Map k a -> Map k a adjust f k m = adjustWithKey (\_ x -> f x) k m -- | /O(log n)/. Adjust a value at a specific key. When the key is not -- a member of the map, the original map is returned. -- -- > let f key x = (show key) ++ ":new " ++ x -- > adjustWithKey f 5 (fromList [(5,"a"), (3,"b")]) == fromList [(3, "b"), (5, "5:new a")] -- > adjustWithKey f 7 (fromList [(5,"a"), (3,"b")]) == fromList [(3, "b"), (5, "a")] -- > adjustWithKey f 7 empty == empty adjustWithKey :: (Ord k, Binary k, Binary a) => (k -> a -> a) -> k -> Map k a -> Map k a adjustWithKey f k m = updateWithKey (\k' x' -> Just (f k' x')) k m -- | /O(log n)/. The expression (@'update' f k map@) updates the value @x@ -- at @k@ (if it is in the map). If (@f x@) is 'Nothing', the element is -- deleted. If it is (@'Just' y@), the key @k@ is bound to the new value @y@. -- -- > let f x = if x == "a" then Just "new a" else Nothing -- > update f 5 (fromList [(5,"a"), (3,"b")]) == fromList [(3, "b"), (5, "new a")] -- > update f 7 (fromList [(5,"a"), (3,"b")]) == fromList [(3, "b"), (5, "a")] -- > update f 3 (fromList [(5,"a"), (3,"b")]) == singleton 5 "a" update :: (Ord k, Binary k, Binary a) => (a -> Maybe a) -> k -> Map k a -> Map k a update f k m = updateWithKey (\_ x -> f x) k m -- | /O(log n)/. The expression (@'updateWithKey' f k map@) updates the -- value @x@ at @k@ (if it is in the map). If (@f k x@) is 'Nothing', -- the element is deleted. If it is (@'Just' y@), the key @k@ is bound -- to the new value @y@. -- -- > let f k x = if x == "a" then Just ((show k) ++ ":new a") else Nothing -- > updateWithKey f 5 (fromList [(5,"a"), (3,"b")]) == fromList [(3, "b"), (5, "5:new a")] -- > updateWithKey f 7 (fromList [(5,"a"), (3,"b")]) == fromList [(3, "b"), (5, "a")] -- > updateWithKey f 3 (fromList [(5,"a"), (3,"b")]) == singleton 5 "a" updateWithKey :: (Ord k, Binary k, Binary a) => (k -> a -> Maybe a) -> k -> Map k a -> Map k a updateWithKey f k m = snd (updateLookupWithKey f k m) -- | /O(log n)/. Lookup and update. See also 'updateWithKey'. -- The function returns changed value, if it is updated. -- Returns the original key value if the map entry is deleted. -- -- > let f k x = if x == "a" then Just ((show k) ++ ":new a") else Nothing -- > updateLookupWithKey f 5 (fromList [(5,"a"), (3,"b")]) == (Just "5:new a", fromList [(3, "b"), (5, "5:new a")]) -- > updateLookupWithKey f 7 (fromList [(5,"a"), (3,"b")]) == (Nothing, fromList [(3, "b"), (5, "a")]) -- > updateLookupWithKey f 3 (fromList [(5,"a"), (3,"b")]) == (Just "b", singleton 5 "a") updateLookupWithKey :: (Ord k, Binary k, Binary a) => (k -> a -> Maybe a) -> k -> Map k a -> (Maybe a,Map k a) updateLookupWithKey f k Empty = (Nothing,Empty) updateLookupWithKey f k m@Existing{index=index,uniq=uniq,range=range,mapSize=mapSize} = unsafePerformIO $ withMVar index $ \idx -> do ls <- Index.lookupList idx k case findValue range ls of Nothing -> return (Nothing, m) Just valBS -> do let val = decodeStrict valBS newVal = f k val mkWeak valBS index Nothing u <- readIORef uniq modifyIORef uniq succ Index.insert idx k u newVal let newSize = case isJust newVal of False -> mapSize-1 True -> mapSize return (newVal `mplus` Just val, Existing{index=index,uniq=uniq,range=addToRange u range,mapSize=newSize}) -- | /O(log n)/. The expression (@'alter' f k map@) alters the value @x@ at @k@, or absence thereof. -- 'alter' can be used to insert, delete, or update a value in a 'Map'. -- In short : @'lookup' k ('alter' f k m) = f ('lookup' k m)@. -- -- > let f _ = Nothing -- > alter f 7 (fromList [(5,"a"), (3,"b")]) == fromList [(3, "b"), (5, "a")] -- > alter f 5 (fromList [(5,"a"), (3,"b")]) == singleton 3 "b" -- > -- > let f _ = Just "c" -- > alter f 7 (fromList [(5,"a"), (3,"b")]) == fromList [(3, "b"), (5, "a"), (7, "c")] -- > alter f 5 (fromList [(5,"a"), (3,"b")]) == fromList [(3, "b"), (5, "c")] alter :: (Ord k, Binary k, Binary a) => (Maybe a -> Maybe a) -> k -> Map k a -> Map k a alter f k m = case f (lookup k m) of Nothing -> delete k m Just val -> insert k val m -- | /O(log n*m)/. -- The expression (@'union' t1 t2@) takes the left-biased union of @t1@ and @t2@. -- It prefers @t1@ when duplicate keys are encountered, -- i.e. (@'union' == 'unionWith' 'const'@). -- -- > union (fromList [(5, "a"), (3, "b")]) (fromList [(5, "A"), (7, "C")]) == fromList [(3, "b"), (5, "a"), (7, "C")] union :: (Ord k, Binary k, Binary a) => Map k a -> Map k a -> Map k a union = unionWith const -- | /O(log n*m)/. Union with a combining function. -- -- > unionWith (++) (fromList [(5, "a"), (3, "b")]) (fromList [(5, "A"), (7, "C")]) == fromList [(3, "b"), (5, "aA"), (7, "C")] unionWith :: (Ord k, Binary k, Binary a) => (a -> a -> a) -> Map k a -> Map k a -> Map k a unionWith f m1 m2 = unionWithKey (\_ x y -> f x y) m1 m2 -- | /O(log n*m)/. -- Union with a combining function. -- -- > let f key new_value old_value = (show key) ++ ":" ++ new_value ++ "|" ++ old_value -- > unionWithKey f (fromList [(5, "a"), (3, "b")]) (fromList [(5, "A"), (7, "C")]) == fromList [(3, "b"), (5, "5:a|A"), (7, "C")] unionWithKey :: (Ord k, Binary k, Binary a) => (k -> a -> a -> a) -> Map k a -> Map k a -> Map k a unionWithKey f t1 t2 = foldl' (\m (k,v) -> insertWithKey f k v m) t2 (toList t1) -- | The union of a list of maps: -- (@'unions' == 'Prelude.foldl' 'union' 'empty'@). -- -- > unions [(fromList [(5, "a"), (3, "b")]), (fromList [(5, "A"), (7, "C")]), (fromList [(5, "A3"), (3, "B3")])] -- > == fromList [(3, "b"), (5, "a"), (7, "C")] -- > unions [(fromList [(5, "A3"), (3, "B3")]), (fromList [(5, "A"), (7, "C")]), (fromList [(5, "a"), (3, "b")])] -- > == fromList [(3, "B3"), (5, "A3"), (7, "C")] unions :: (Ord k, Binary k, Binary a) => [Map k a] -> Map k a unions ts = foldl' union empty ts -- | The union of a list of maps, with a combining operation: -- (@'unionsWith' f == 'Prelude.foldl' ('unionWith' f) 'empty'@). -- -- > unionsWith (++) [(fromList [(5, "a"), (3, "b")]), (fromList [(5, "A"), (7, "C")]), (fromList [(5, "A3"), (3, "B3")])] -- > == fromList [(3, "bB3"), (5, "aAA3"), (7, "C")] unionsWith :: (Ord k, Binary k, Binary a) => (a -> a -> a) -> [Map k a] -> Map k a unionsWith f ts = foldl' (unionWith f) empty ts -- | /O(n)/. Map a function over all values in the map. -- -- > map (++ "x") (fromList [(5,"a"), (3,"b")]) == fromList [(3, "bx"), (5, "ax")] map :: (Ord k, Binary k, Binary a, Binary b) => (a -> b) -> Map k a -> Map k b map f m = mapWithKey (\_ x -> f x) m -- | /O(n)/. Map a function over all values in the map. -- -- > let f key x = (show key) ++ ":" ++ x -- > mapWithKey f (fromList [(5,"a"), (3,"b")]) == fromList [(3, "3:b"), (5, "5:a")] mapWithKey :: (Ord k, Binary k, Binary a, Binary b) => (k -> a -> b) -> Map k a -> Map k b mapWithKey f m = fromDistinctAscList [ (k, f k x) | (k,x) <- toList m ] -- | /O(n*log n)/. -- @'mapKeys' f s@ is the map obtained by applying @f@ to each key of @s@. -- -- The size of the result may be smaller if @f@ maps two or more distinct -- keys to the same new key. In this case the value at the smallest of -- these keys is retained. -- -- > mapKeys (+ 1) (fromList [(5,"a"), (3,"b")]) == fromList [(4, "b"), (6, "a")] -- > mapKeys (\ _ -> 1) (fromList [(1,"b"), (2,"a"), (3,"d"), (4,"c")]) == singleton 1 "c" -- > mapKeys (\ _ -> 3) (fromList [(1,"b"), (2,"a"), (3,"d"), (4,"c")]) == singleton 3 "c" mapKeys :: (Ord k2,Binary k1,Binary k2,Binary a) => (k1->k2) -> Map k1 a -> Map k2 a mapKeys = mapKeysWith (\x _ -> x) -- | /O(n*log n)/. -- @'mapKeysWith' c f s@ is the map obtained by applying @f@ to each key of @s@. -- -- The size of the result may be smaller if @f@ maps two or more distinct -- keys to the same new key. In this case the associated values will be -- combined using @c@. -- -- > mapKeysWith (++) (\ _ -> 1) (fromList [(1,"b"), (2,"a"), (3,"d"), (4,"c")]) == singleton 1 "cdab" -- > mapKeysWith (++) (\ _ -> 3) (fromList [(1,"b"), (2,"a"), (3,"d"), (4,"c")]) == singleton 3 "cdab" mapKeysWith :: (Ord k2, Binary k1, Binary k2, Binary a) => (a -> a -> a) -> (k1->k2) -> Map k1 a -> Map k2 a mapKeysWith c f m = fromListWith c [ (f x,y) | (x,y) <- toList m ] -- | /O(n)/. -- @'mapKeysMonotonic' f s == 'mapKeys' f s@, but works only when @f@ -- is strictly monotonic. -- That is, for any values @x@ and @y@, if @x@ < @y@ then @f x@ < @f y@. -- /The precondition is not checked./ -- Semi-formally, we have: -- -- > and [x < y ==> f x < f y | x <- ls, y <- ls] -- > ==> mapKeysMonotonic f s == mapKeys f s -- > where ls = keys s -- -- This means that @f@ maps distinct original keys to distinct resulting keys. -- This function has better performance than 'mapKeys'. -- -- > mapKeysMonotonic (\ k -> k * 2) (fromList [(5,"a"), (3,"b")]) == fromList [(6, "b"), (10, "a")] -- > valid (mapKeysMonotonic (\ k -> k * 2) (fromList [(5,"a"), (3,"b")])) == True -- > valid (mapKeysMonotonic (\ _ -> 1) (fromList [(5,"a"), (3,"b")])) == False mapKeysMonotonic :: (Binary k1, Binary k2, Binary a) => (k1->k2) -> Map k1 a -> Map k2 a mapKeysMonotonic f m = fromDistinctAscList [ (f x, y) | (x,y) <- toList m ] -- | /O(n)/. Fold the values in the map, such that -- @'fold' f z == 'Prelude.foldr' f z . 'elems'@. -- For example, -- -- > elems map = fold (:) [] map -- -- > let f a len = len + (length a) -- > fold f 0 (fromList [(5,"a"), (3,"bbb")]) == 4 fold :: (Binary k, Binary a) => (a -> b -> b) -> b -> Map k a -> b fold f z m = foldWithKey (\_ x' z' -> f x' z') z m -- | /O(n)/. Fold the keys and values in the map, such that -- @'foldWithKey' f z == 'Prelude.foldr' ('uncurry' f) z . 'toAscList'@. -- For example, -- -- > keys map = foldWithKey (\k x ks -> k:ks) [] map -- -- > let f k a result = result ++ "(" ++ (show k) ++ ":" ++ a ++ ")" -- > foldWithKey f "Map: " (fromList [(5,"a"), (3,"b")]) == "Map: (5:a)(3:b)" foldWithKey :: (Binary k, Binary a) => (k -> a -> b -> b) -> b -> Map k a -> b foldWithKey f z = Prelude.foldr (uncurry f) z . toList -- | /O(n)/. -- Return all elements of the map in the ascending order of their keys. -- -- > elems (fromList [(5,"a"), (3,"b")]) == ["b","a"] -- > elems empty == [] elems :: (Binary k, Binary a) => Map k a -> [a] elems = Prelude.map snd . toList -- | /O(n)/. Return all keys of the map in ascending order. -- -- > keys (fromList [(5,"a"), (3,"b")]) == [3,5] -- > keys empty == [] keys :: (Binary k, Binary a) => Map k a -> [k] keys = Prelude.map fst . toList -- | /O(n)/. The set of all keys of the map. -- -- > keysSet (fromList [(5,"a"), (3,"b")]) == Data.Set.fromList [3,5] -- > keysSet empty == Data.Set.empty keysSet :: (Ord k, Binary k, Binary a) => Map k a -> Set.Set k keysSet m = Set.fromDistinctAscList (keys m) -- | /O(n)/. Return all key\/value pairs in the map in ascending key order. -- -- > assocs (fromList [(5,"a"), (3,"b")]) == [(3,"b"), (5,"a")] -- > assocs empty == [] assocs :: (Binary k, Binary a) => Map k a -> [(k,a)] assocs m = toList m {-# SPECIALISE fromList :: (Binary a) => [(Strict.ByteString,a)] -> Map Strict.ByteString a #-} {-# SPECIALISE fromList :: (Binary a) => [(Int,a)] -> Map Int a #-} -- | /O(n*log n)/. Build a map from a list of key\/value pairs. See also 'fromAscList'. -- If the list contains more than one value for the same key, the last value -- for the key is retained. -- -- > fromList [] == empty -- > fromList [(5,"a"), (3,"b"), (5, "c")] == fromList [(5,"c"), (3,"b")] -- > fromList [(5,"c"), (3,"b"), (5, "a")] == fromList [(5,"a"), (3,"b")] fromList :: (Ord k, Binary k, Binary a) => [(k,a)] -> Map k a fromList [] = Empty fromList ls = unsafePerformIO $ do idx <- Index.newIndex let loop n _ | n `seq` False = undefined loop n [] = return n loop n ((k,v):rs) | k `seq` v `seq` True = do keyCursor <- Index.insertKey idx k oldData <- Index.peekKeyCursorData keyCursor newData <- Index.newDataCursor (indexBuffer idx) 0 (Just (encode v)) Index.pushNewDataCursor keyCursor newData loop (if oldData==nullPtr then n+1 else n) rs size <- loop 0 ls uniq <- newIORef 1 index <- newMVar idx return $ Existing{index=index,uniq=uniq,range=addToRange 0 [],mapSize=size} -- | /O(n*log n)/. Build a map from a list of key\/value pairs with a combining function. See also 'fromAscListWith'. -- -- > fromListWith (++) [(5,"a"), (5,"b"), (3,"b"), (3,"a"), (5,"a")] == fromList [(3, "ab"), (5, "aba")] -- > fromListWith (++) [] == empty fromListWith :: (Ord k, Binary k, Binary a) => (a -> a -> a) -> [(k,a)] -> Map k a fromListWith f xs = fromListWithKey (\_ x y -> f x y) xs -- | /O(n*log n)/. Build a map from a list of key\/value pairs with a combining function. See also 'fromAscListWithKey'. -- -- > let f k a1 a2 = (show k) ++ a1 ++ a2 -- > fromListWithKey f [(5,"a"), (5,"b"), (3,"b"), (3,"a"), (5,"a")] == fromList [(3, "3ab"), (5, "5a5ba")] -- > fromListWithKey f [] == empty fromListWithKey :: (Ord k, Binary k, Binary a) => (k -> a -> a -> a) -> [(k,a)] -> Map k a fromListWithKey f [] = empty fromListWithKey f ls = unsafePerformIO $ do idx <- Index.newIndex let loop n _ | n `seq` False = undefined loop n [] = return n loop n ((k,v):rs) = do keyCursor <- Index.insertKey idx k oldData <- Index.getDataFromPointer keyCursor let newVal = case oldData of ((_,Just old):_) -> f k v (decodeStrict old) _ -> v newData <- Index.newDataCursor (indexBuffer idx) 0 (Just (encode newVal)) Index.pushNewDataCursor keyCursor newData loop (if Prelude.null oldData then n+1 else n) rs size <- loop 0 ls uniq <- newIORef 1 index <- newMVar idx return $ Existing{index=index,uniq=uniq,range=addToRange 0 [],mapSize=size} -- | /O(n)/. Convert to a list of key\/value pairs. -- -- > toList (fromList [(5,"a"), (3,"b")]) == [(3,"b"), (5,"a")] -- > toList empty == [] toList :: (Binary k, Binary a) => Map k a -> [(k,a)] toList Empty = [] toList Existing{index=index,range=range} = unsafePerformIO $ do keys <- withMVar index $ Index.listKeyPointers let loop [] = return [] -- withMVar index Index.touchIndex >> return [] loop (keyCursor:xs) = unsafeInterleaveIO $ do mkWeak keyCursor index Nothing ls <- Index.getDataFromPointer keyCursor case findValue range ls of Nothing -> loop xs Just bs -> do key <- Index.getKeyFromPointer keyCursor mkWeak bs index Nothing mkWeak key index Nothing let pair = (decodeStrict key, decodeStrict bs) liftM (pair:) (loop xs) loop (IArray.elems keys) -- | /O(n)/. Convert to an ascending list. -- -- > toAscList (fromList [(5,"a"), (3,"b")]) == [(3,"b"), (5,"a")] toAscList :: (Binary k, Binary a) =>Map k a -> [(k,a)] toAscList = toList -- | /O(n)/. Build a map from an ascending list in linear time. -- /The precondition (input list is ascending) is not checked./ -- -- > fromAscList [(3,"b"), (5,"a")] == fromList [(3, "b"), (5, "a")] -- > fromAscList [(3,"b"), (5,"a"), (5,"b")] == fromList [(3, "b"), (5, "b")] -- > valid (fromAscList [(3,"b"), (5,"a"), (5,"b")]) == True -- > valid (fromAscList [(5,"a"), (3,"b"), (5,"b")]) == False fromAscList :: (Eq k, Binary k, Binary a) => [(k,a)] -> Map k a fromAscList xs = fromAscListWithKey (\_ x _ -> x) xs -- | /O(n)/. Build a map from an ascending list in linear time with a combining function for equal keys. -- /The precondition (input list is ascending) is not checked./ -- -- > fromAscListWith (++) [(3,"b"), (5,"a"), (5,"b")] == fromList [(3, "b"), (5, "ba")] -- > valid (fromAscListWith (++) [(3,"b"), (5,"a"), (5,"b")]) == True -- > valid (fromAscListWith (++) [(5,"a"), (3,"b"), (5,"b")]) == False fromAscListWith :: (Eq k, Binary k, Binary a) => (a -> a -> a) -> [(k,a)] -> Map k a fromAscListWith f xs = fromAscListWithKey (\_ x y -> f x y) xs -- | /O(n)/. Build a map from an ascending list in linear time with a -- combining function for equal keys. -- /The precondition (input list is ascending) is not checked./ -- -- > let f k a1 a2 = (show k) ++ ":" ++ a1 ++ a2 -- > fromAscListWithKey f [(3,"b"), (5,"a"), (5,"b"), (5,"b")] == fromList [(3, "b"), (5, "5:b5:ba")] -- > valid (fromAscListWithKey f [(3,"b"), (5,"a"), (5,"b"), (5,"b")]) == True -- > valid (fromAscListWithKey f [(5,"a"), (3,"b"), (5,"b"), (5,"b")]) == False fromAscListWithKey :: (Eq k, Binary k, Binary a) => (k -> a -> a -> a) -> [(k,a)] -> Map k a fromAscListWithKey f xs = fromDistinctAscList (combineEq f xs) where -- [combineEq f xs] combines equal elements with function [f] in an ordered list [xs] combineEq _ xs' = case xs' of [] -> [] [x] -> [x] (x:xx) -> combineEq' x xx 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' -- | /O(n)/. Build a map from an ascending list of distinct elements in linear time. -- /The precondition is not checked./ -- -- > fromDistinctAscList [(3,"b"), (5,"a")] == fromList [(3, "b"), (5, "a")] -- > valid (fromDistinctAscList [(3,"b"), (5,"a")]) == True -- > valid (fromDistinctAscList [(3,"b"), (5,"a"), (5,"b")]) == False fromDistinctAscList :: (Binary k, Binary a) => [(k,a)] -> Map k a fromDistinctAscList [] = Empty fromDistinctAscList ls = unsafePerformIO $ do idx <- Index.newIndex n <- foldM (\s (k,v) -> do keyCursor <- Index.insertLargestKey idx k dataCursor <- Index.newDataCursor (indexBuffer idx) 0 (Just $ encode v) Index.pushNewDataCursor keyCursor dataCursor return $! s+1) 0 ls index <- newMVar idx uniq <- newIORef 1 return Existing{index=index,uniq=uniq,range=addToRange 0 [],mapSize=n} -- | /O(n)/. Filter all values that satisfy the predicate. -- -- > filter (> "a") (fromList [(5,"a"), (3,"b")]) == singleton 3 "b" -- > filter (> "x") (fromList [(5,"a"), (3,"b")]) == empty -- > filter (< "a") (fromList [(5,"a"), (3,"b")]) == empty filter :: (Ord k, Binary k, Binary a) => (a -> Bool) -> Map k a -> Map k a filter p m = filterWithKey (\_ x -> p x) m -- FIXME: optimize this. -- | /O(n)/. Filter all keys\/values that satisfy the predicate. -- -- > filterWithKey (\k _ -> k > 4) (fromList [(5,"a"), (3,"b")]) == singleton 5 "a" filterWithKey :: (Ord k, Binary k, Binary a) => (k -> a -> Bool) -> Map k a -> Map k a filterWithKey p m = fromDistinctAscList [ (k, v) | (k,v) <- toList m, p k v ] -- | /O(n)/. Partition the map according to a predicate. The first -- map contains all elements that satisfy the predicate, the second all -- elements that fail the predicate. See also 'split'. -- -- > partition (> "a") (fromList [(5,"a"), (3,"b")]) == (singleton 3 "b", singleton 5 "a") -- > partition (< "x") (fromList [(5,"a"), (3,"b")]) == (fromList [(3, "b"), (5, "a")], empty) -- > partition (> "x") (fromList [(5,"a"), (3,"b")]) == (empty, fromList [(3, "b"), (5, "a")]) partition :: (Ord k, Binary k, Binary a) => (a -> Bool) -> Map k a -> (Map k a,Map k a) partition p = partitionWithKey (\_ -> p) -- | /O(n)/. Partition the map according to a predicate. The first -- map contains all elements that satisfy the predicate, the second all -- elements that fail the predicate. See also 'split'. -- -- > partitionWithKey (\ k _ -> k > 3) (fromList [(5,"a"), (3,"b")]) == (singleton 5 "a", singleton 3 "b") -- > partitionWithKey (\ k _ -> k < 7) (fromList [(5,"a"), (3,"b")]) == (fromList [(3, "b"), (5, "a")], empty) -- > partitionWithKey (\ k _ -> k > 7) (fromList [(5,"a"), (3,"b")]) == (empty, fromList [(3, "b"), (5, "a")]) partitionWithKey :: (Ord k, Binary k, Binary a) => (k -> a -> Bool) -> Map k a -> (Map k a,Map k a) partitionWithKey p m = mapEitherWithKey (\k x -> if p k x then Left x else Right x) m -- | /O(n)/. Map values and collect the 'Just' results. -- -- > let f x = if x == "a" then Just "new a" else Nothing -- > mapMaybe f (fromList [(5,"a"), (3,"b")]) == singleton 5 "new a" mapMaybe :: (Ord k, Binary k, Binary a, Binary b) => (a -> Maybe b) -> Map k a -> Map k b mapMaybe f m = mapMaybeWithKey (\_ x -> f x) m -- | /O(n)/. Map keys\/values and collect the 'Just' results. -- -- > let f k _ = if k < 5 then Just ("key : " ++ (show k)) else Nothing -- > mapMaybeWithKey f (fromList [(5,"a"), (3,"b")]) == singleton 3 "key : 3" mapMaybeWithKey :: (Ord k, Binary k, Binary a, Binary b) => (k -> a -> Maybe b) -> Map k a -> Map k b mapMaybeWithKey f m = fromDistinctAscList [ (k, v) | (k,x) <- toList m, Just v <- [f k x] ] -- | /O(n)/. Map values and separate the 'Left' and 'Right' results. -- -- > let f a = if a < "c" then Left a else Right a -- > mapEither f (fromList [(5,"a"), (3,"b"), (1,"x"), (7,"z")]) -- > == (fromList [(3,"b"), (5,"a")], fromList [(1,"x"), (7,"z")]) -- > -- > mapEither (\ a -> Right a) (fromList [(5,"a"), (3,"b"), (1,"x"), (7,"z")]) -- > == (empty, fromList [(5,"a"), (3,"b"), (1,"x"), (7,"z")]) mapEither :: (Ord k, Binary k, Binary a, Binary b, Binary c) => (a -> Either b c) -> Map k a -> (Map k b, Map k c) mapEither f m = mapEitherWithKey (\_ x -> f x) m -- The key doesn't change. Don't re-encode it. Copy bytestring instead. -- | /O(n)/. Map keys\/values and separate the 'Left' and 'Right' results. -- -- > let f k a = if k < 5 then Left (k * 2) else Right (a ++ a) -- > mapEitherWithKey f (fromList [(5,"a"), (3,"b"), (1,"x"), (7,"z")]) -- > == (fromList [(1,2), (3,6)], fromList [(5,"aa"), (7,"zz")]) -- > -- > mapEitherWithKey (\_ a -> Right a) (fromList [(5,"a"), (3,"b"), (1,"x"), (7,"z")]) -- > == (empty, fromList [(1,"x"), (3,"b"), (5,"a"), (7,"z")]) mapEitherWithKey :: (Ord k, Binary k, Binary a, Binary c, Binary b) => (k -> a -> Either b c) -> Map k a -> (Map k b, Map k c) mapEitherWithKey f m = unsafePerformIO $ do idxL <- Index.newIndex idxR <- Index.newIndex (s1,s2) <- foldM (\(s1,s2) (k,v) -> s1 `seq` s2 `seq` do let cond = f k v (idx,v',s1',s2') = case cond of Left v' -> (idxL,encode v',s1+1,s2) Right v' -> (idxR,encode v',s1,s2+1) keyCursor <- Index.insertLargestKey idx k dataCursor <- Index.newDataCursor (indexBuffer idx) 0 (Just v') Index.pushNewDataCursor keyCursor dataCursor return $! (s1',s2')) (0,0) (toList m) indexL <- newMVar idxL indexR <- newMVar idxR uniqL <- newIORef 1 uniqR <- newIORef 1 return $ (Existing{index=indexL,uniq=uniqR,range=addToRange 0 [],mapSize=s1} ,Existing{index=indexR,uniq=uniqL,range=addToRange 0 [],mapSize=s2}) -- | /O(log n)/. The minimal key of the map. Calls 'error' is the map is empty. -- -- > findMin (fromList [(5,"a"), (3,"b")]) == (3,"b") -- > findMin empty Error: empty map has no minimal element findMin :: (Binary k, Binary a) => Map k a -> (k,a) findMin m = case m of Empty -> err Existing{index=index,range=range} -> unsafePerformIO $ withMVar index $ \idx -> do mbMin <- findMinKey idx range case mbMin of Nothing -> err Just (keyCursor,val) -> do key <- Index.getKeyFromPointer keyCursor mkWeak key index Nothing mkWeak val index Nothing return (decodeStrict key, decodeStrict val) where err = error "Map.findMin: empty map has no minimal element" -- | /O(log n)/. The maximal key of the map. Calls 'error' is the map is empty. -- -- > findMax (fromList [(5,"a"), (3,"b")]) == (5,"a") -- > findMax empty Error: empty map has no maximal element findMax :: (Binary k, Binary a) => Map k a -> (k,a) findMax m = case m of Empty -> err Existing{index=index,range=range} -> unsafePerformIO $ withMVar index $ \idx -> do mbMin <- findMaxKey idx range case mbMin of Nothing -> err Just (keyCursor,val) -> do key <- Index.getKeyFromPointer keyCursor mkWeak key index Nothing mkWeak val index Nothing return (decodeStrict key, decodeStrict val) where err = error "Map.findMax: empty map has no maximal element" -- | /O(log n)/. Delete the minimal key. Returns an empty map if the map is empty. -- -- > deleteMin (fromList [(5,"a"), (3,"b"), (7,"c")]) == fromList [(5,"a"), (7,"c")] -- > deleteMin empty == empty deleteMin :: (Binary k, Binary a) => Map k a -> Map k a deleteMin = snd . deleteFindMin -- | /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 empty == (Error: can not return the minimal element of an empty map,empty) deleteFindMin :: (Binary k, Binary a) => Map k a -> ((k,a), Map k a) deleteFindMin m = case m of Empty -> (deleteFindMinErr, Empty) Existing{index=index,uniq=uniq,range=range,mapSize=mapSize} -> unsafePerformIO $ withMVar index $ \idx -> do mbMin <- findMinKey idx range case mbMin of Nothing -> return (deleteFindMinErr, Empty) Just (keyCursor,val) -> do u <- readIORef uniq modifyIORef uniq succ dataCursor <- Index.newDataCursor (indexBuffer idx) u Nothing Index.pushNewDataCursor keyCursor dataCursor key <- Index.getKeyFromPointer keyCursor mkWeak key index Nothing mkWeak val index Nothing return $ ((decodeStrict key,decodeStrict val),Existing{index=index,uniq=uniq,range=addToRange u range,mapSize=mapSize-1}) where deleteFindMinErr = error "Data.CompactMap.deleteFindMin: can not return the minimal element of an empty map" findMinKey = findCornerKey Index.extractLeft Index.extractRight findMaxKey = findCornerKey Index.extractRight Index.extractLeft findCornerKey left right (Index orig buffer) range = do s <- Index.getSize orig if s == 0 then return Nothing else do let loop ptr | ptr == nullPtr = return Nothing loop ptr = do res <- loop =<< left ptr case res of Just val -> return $ Just val Nothing -> do keyCursor <- Index.extractElemIdx ptr ls <- Index.getDataFromPointer keyCursor case findValue range ls of Just val -> return $ Just (keyCursor, val) _ -> loop =<< right ptr loop orig {-------------------------------------------------------------------- Utilities --------------------------------------------------------------------} decodeStrict bs = decode (Lazy.fromChunks [bs]) haveOldValue range ls = isJust (findValue range ls) withExisting Empty fn = do idx <- newMVar =<< Index.newIndex uniq <- newIORef 0 fn (Existing idx uniq [] 0) withExisting m fn = fn m findValue range [] = Nothing findValue range ((uniqId, value):rs) | uniqId `isInRange` range = value | otherwise = findValue range rs isInRange :: Int -> [Range] -> Bool isInRange i [] = False isInRange i (Range x y:rs) | i > x = False | i < y = isInRange i rs | otherwise = True addToRange :: Int -> [Range] -> [Range] addToRange i [] = [Range i i] addToRange i (Range x y:rs) = merge (Range i i:Range x y:rs) merge [] = [] merge [x] = [x] merge (Range x y:Range a b:rs) | y == a+1 = merge (Range x b:rs) | otherwise = Range x y:merge (Range a b:rs)