{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE CPP #-}
-- | Warning: This module should be considered highly experimental.
module Data.Containers where
import Prelude hiding (lookup)
import Data.Maybe (fromMaybe)
#if MIN_VERSION_containers(0, 5, 0)
import qualified Data.Map.Strict as Map
#else
import qualified Data.Map as Map
#endif
import qualified Data.HashMap.Strict as HashMap
import Data.Hashable (Hashable)
import qualified Data.Set as Set
import qualified Data.HashSet as HashSet
import Data.Monoid (Monoid (..))
import Data.Semigroup (Semigroup)
import Data.MonoTraversable (MonoFunctor(..), MonoFoldable, MonoTraversable, Element)
import qualified Data.IntMap as IntMap
import Data.Function (on)
import qualified Data.List as List
import qualified Data.IntSet as IntSet
import qualified Data.Text.Lazy as LText
import qualified Data.Text as Text
import qualified Data.ByteString.Lazy as LByteString
import qualified Data.ByteString as ByteString
import Control.Arrow ((***))
import Data.GrowingAppend
class (Monoid set, Semigroup set, MonoFoldable set, Eq (ContainerKey set), GrowingAppend set) => SetContainer set where
type ContainerKey set
member :: ContainerKey set -> set -> Bool
notMember :: ContainerKey set -> set -> Bool
union :: set -> set -> set
difference :: set -> set -> set
intersection :: set -> set -> set
instance Ord k => SetContainer (Map.Map k v) where
type ContainerKey (Map.Map k v) = k
member = Map.member
{-# INLINE member #-}
notMember = Map.notMember
{-# INLINE notMember #-}
union = Map.union
{-# INLINE union #-}
difference = Map.difference
{-# INLINE difference #-}
intersection = Map.intersection
{-# INLINE intersection #-}
instance (Eq key, Hashable key) => SetContainer (HashMap.HashMap key value) where
type ContainerKey (HashMap.HashMap key value) = key
member = HashMap.member
{-# INLINE member #-}
notMember k = not . HashMap.member k
{-# INLINE notMember #-}
union = HashMap.union
{-# INLINE union #-}
difference = HashMap.difference
{-# INLINE difference #-}
intersection = HashMap.intersection
{-# INLINE intersection #-}
instance SetContainer (IntMap.IntMap value) where
type ContainerKey (IntMap.IntMap value) = Int
member = IntMap.member
{-# INLINE member #-}
notMember = IntMap.notMember
{-# INLINE notMember #-}
union = IntMap.union
{-# INLINE union #-}
difference = IntMap.difference
{-# INLINE difference #-}
intersection = IntMap.intersection
{-# INLINE intersection #-}
instance Ord element => SetContainer (Set.Set element) where
type ContainerKey (Set.Set element) = element
member = Set.member
{-# INLINE member #-}
notMember = Set.notMember
{-# INLINE notMember #-}
union = Set.union
{-# INLINE union #-}
difference = Set.difference
{-# INLINE difference #-}
intersection = Set.intersection
{-# INLINE intersection #-}
instance (Eq element, Hashable element) => SetContainer (HashSet.HashSet element) where
type ContainerKey (HashSet.HashSet element) = element
member = HashSet.member
{-# INLINE member #-}
notMember e = not . HashSet.member e
{-# INLINE notMember #-}
union = HashSet.union
{-# INLINE union #-}
difference = HashSet.difference
{-# INLINE difference #-}
intersection = HashSet.intersection
{-# INLINE intersection #-}
instance SetContainer IntSet.IntSet where
type ContainerKey IntSet.IntSet = Int
member = IntSet.member
{-# INLINE member #-}
notMember = IntSet.notMember
{-# INLINE notMember #-}
union = IntSet.union
{-# INLINE union #-}
difference = IntSet.difference
{-# INLINE difference #-}
intersection = IntSet.intersection
{-# INLINE intersection #-}
instance Eq key => SetContainer [(key, value)] where
type ContainerKey [(key, value)] = key
member k = List.any ((== k) . fst)
{-# INLINE member #-}
notMember k = not . member k
{-# INLINE notMember #-}
union = List.unionBy ((==) `on` fst)
{-# INLINE union #-}
x `difference` y =
loop x
where
loop [] = []
loop ((k, v):rest) =
case lookup k y of
Nothing -> (k, v) : loop rest
Just _ -> loop rest
intersection = List.intersectBy ((==) `on` fst)
{-# INLINE intersection #-}
-- | A guaranteed-polymorphic @Map@, which allows for more polymorphic versions
-- of functions.
class PolyMap map where
differenceMap :: map value1 -> map value2 -> map value1
{-
differenceWithMap :: (value1 -> value2 -> Maybe value1)
-> map value1 -> map value2 -> map value1
-}
intersectionMap :: map value1 -> map value2 -> map value1
intersectionWithMap :: (value1 -> value2 -> value3)
-> map value1 -> map value2 -> map value3
instance Ord key => PolyMap (Map.Map key) where
differenceMap = Map.difference
{-# INLINE differenceMap #-}
--differenceWithMap = Map.differenceWith
intersectionMap = Map.intersection
{-# INLINE intersectionMap #-}
intersectionWithMap = Map.intersectionWith
{-# INLINE intersectionWithMap #-}
instance (Eq key, Hashable key) => PolyMap (HashMap.HashMap key) where
differenceMap = HashMap.difference
{-# INLINE differenceMap #-}
--differenceWithMap = HashMap.differenceWith
intersectionMap = HashMap.intersection
{-# INLINE intersectionMap #-}
intersectionWithMap = HashMap.intersectionWith
{-# INLINE intersectionWithMap #-}
instance PolyMap IntMap.IntMap where
differenceMap = IntMap.difference
{-# INLINE differenceMap #-}
--differenceWithMap = IntMap.differenceWith
intersectionMap = IntMap.intersection
{-# INLINE intersectionMap #-}
intersectionWithMap = IntMap.intersectionWith
{-# INLINE intersectionWithMap #-}
class (MonoTraversable map, SetContainer map) => IsMap map where
-- | In some cases, @MapValue@ and @Element@ will be different, e.g., the
-- @IsMap@ instance of associated lists.
type MapValue map
lookup :: ContainerKey map -> map -> Maybe (MapValue map)
insertMap :: ContainerKey map -> MapValue map -> map -> map
deleteMap :: ContainerKey map -> map -> map
singletonMap :: ContainerKey map -> MapValue map -> map
mapFromList :: [(ContainerKey map, MapValue map)] -> map
mapToList :: map -> [(ContainerKey map, MapValue map)]
findWithDefault :: MapValue map -> ContainerKey map -> map -> MapValue map
findWithDefault def key = fromMaybe def . lookup key
insertWith :: (MapValue map -> MapValue map -> MapValue map)
-> ContainerKey map
-> MapValue map
-> map
-> map
insertWith f k v m =
v' `seq` insertMap k v' m
where
v' =
case lookup k m of
Nothing -> v
Just vold -> f v vold
insertWithKey
:: (ContainerKey map -> MapValue map -> MapValue map -> MapValue map)
-> ContainerKey map
-> MapValue map
-> map
-> map
insertWithKey f k v m =
v' `seq` insertMap k v' m
where
v' =
case lookup k m of
Nothing -> v
Just vold -> f k v vold
insertLookupWithKey
:: (ContainerKey map -> MapValue map -> MapValue map -> MapValue map)
-> ContainerKey map
-> MapValue map
-> map
-> (Maybe (MapValue map), map)
insertLookupWithKey f k v m =
v' `seq` (mold, insertMap k v' m)
where
(mold, v') =
case lookup k m of
Nothing -> (Nothing, v)
Just vold -> (Just vold, f k v vold)
adjustMap
:: (MapValue map -> MapValue map)
-> ContainerKey map
-> map
-> map
adjustMap f k m =
case lookup k m of
Nothing -> m
Just v ->
let v' = f v
in v' `seq` insertMap k v' m
adjustWithKey
:: (ContainerKey map -> MapValue map -> MapValue map)
-> ContainerKey map
-> map
-> map
adjustWithKey f k m =
case lookup k m of
Nothing -> m
Just v ->
let v' = f k v
in v' `seq` insertMap k v' m
updateMap
:: (MapValue map -> Maybe (MapValue map))
-> ContainerKey map
-> map
-> map
updateMap f k m =
case lookup k m of
Nothing -> m
Just v ->
case f v of
Nothing -> deleteMap k m
Just v' -> v' `seq` insertMap k v' m
updateWithKey
:: (ContainerKey map -> MapValue map -> Maybe (MapValue map))
-> ContainerKey map
-> map
-> map
updateWithKey f k m =
case lookup k m of
Nothing -> m
Just v ->
case f k v of
Nothing -> deleteMap k m
Just v' -> v' `seq` insertMap k v' m
updateLookupWithKey
:: (ContainerKey map -> MapValue map -> Maybe (MapValue map))
-> ContainerKey map
-> map
-> (Maybe (MapValue map), map)
updateLookupWithKey f k m =
case lookup k m of
Nothing -> (Nothing, m)
Just v ->
case f k v of
Nothing -> (Just v, deleteMap k m)
Just v' -> v' `seq` (Just v', insertMap k v' m)
alterMap
:: (Maybe (MapValue map) -> Maybe (MapValue map))
-> ContainerKey map
-> map
-> map
alterMap f k m =
case f mold of
Nothing ->
case mold of
Nothing -> m
Just _ -> deleteMap k m
Just v -> insertMap k v m
where
mold = lookup k m
unionWith
:: (MapValue map -> MapValue map -> MapValue map)
-> map
-> map
-> map
unionWith f x y =
mapFromList $ loop $ mapToList x ++ mapToList y
where
loop [] = []
loop ((k, v):rest) =
case List.lookup k rest of
Nothing -> (k, v) : loop rest
Just v' -> (k, f v v') : loop (deleteMap k rest)
unionWithKey
:: (ContainerKey map -> MapValue map -> MapValue map -> MapValue map)
-> map
-> map
-> map
unionWithKey f x y =
mapFromList $ loop $ mapToList x ++ mapToList y
where
loop [] = []
loop ((k, v):rest) =
case List.lookup k rest of
Nothing -> (k, v) : loop rest
Just v' -> (k, f k v v') : loop (deleteMap k rest)
unionsWith
:: (MapValue map -> MapValue map -> MapValue map)
-> [map]
-> map
unionsWith _ [] = mempty
unionsWith _ [x] = x
unionsWith f (x:y:z) = unionsWith f (unionWith f x y:z)
mapWithKey
:: (ContainerKey map -> MapValue map -> MapValue map)
-> map
-> map
mapWithKey f =
mapFromList . map go . mapToList
where
go (k, v) = (k, f k v)
mapKeysWith
:: (MapValue map -> MapValue map -> MapValue map)
-> (ContainerKey map -> ContainerKey map)
-> map
-> map
mapKeysWith g f =
mapFromList . unionsWith g . map go . mapToList
where
go (k, v) = [(f k, v)]
instance Ord key => IsMap (Map.Map key value) where
type MapValue (Map.Map key value) = value
lookup = Map.lookup
{-# INLINE lookup #-}
insertMap = Map.insert
{-# INLINE insertMap #-}
deleteMap = Map.delete
{-# INLINE deleteMap #-}
singletonMap = Map.singleton
{-# INLINE singletonMap #-}
mapFromList = Map.fromList
{-# INLINE mapFromList #-}
mapToList = Map.toList
{-# INLINE mapToList #-}
findWithDefault = Map.findWithDefault
{-# INLINE findWithDefault #-}
insertWith = Map.insertWith
{-# INLINE insertWith #-}
insertWithKey = Map.insertWithKey
{-# INLINE insertWithKey #-}
insertLookupWithKey = Map.insertLookupWithKey
{-# INLINE insertLookupWithKey #-}
adjustMap = Map.adjust
{-# INLINE adjustMap #-}
adjustWithKey = Map.adjustWithKey
{-# INLINE adjustWithKey #-}
updateMap = Map.update
{-# INLINE updateMap #-}
updateWithKey = Map.updateWithKey
{-# INLINE updateWithKey #-}
updateLookupWithKey = Map.updateLookupWithKey
{-# INLINE updateLookupWithKey #-}
alterMap = Map.alter
{-# INLINE alterMap #-}
unionWith = Map.unionWith
{-# INLINE unionWith #-}
unionWithKey = Map.unionWithKey
{-# INLINE unionWithKey #-}
unionsWith = Map.unionsWith
{-# INLINE unionsWith #-}
mapWithKey = Map.mapWithKey
{-# INLINE mapWithKey #-}
mapKeysWith = Map.mapKeysWith
{-# INLINE mapKeysWith #-}
instance (Eq key, Hashable key) => IsMap (HashMap.HashMap key value) where
type MapValue (HashMap.HashMap key value) = value
lookup = HashMap.lookup
{-# INLINE lookup #-}
insertMap = HashMap.insert
{-# INLINE insertMap #-}
deleteMap = HashMap.delete
{-# INLINE deleteMap #-}
singletonMap = HashMap.singleton
{-# INLINE singletonMap #-}
mapFromList = HashMap.fromList
{-# INLINE mapFromList #-}
mapToList = HashMap.toList
{-# INLINE mapToList #-}
--findWithDefault = HashMap.findWithDefault
insertWith = HashMap.insertWith
{-# INLINE insertWith #-}
--insertWithKey = HashMap.insertWithKey
--insertLookupWithKey = HashMap.insertLookupWithKey
adjustMap = HashMap.adjust
{-# INLINE adjustMap #-}
--adjustWithKey = HashMap.adjustWithKey
--updateMap = HashMap.update
--updateWithKey = HashMap.updateWithKey
--updateLookupWithKey = HashMap.updateLookupWithKey
--alterMap = HashMap.alter
unionWith = HashMap.unionWith
{-# INLINE unionWith #-}
--unionWithKey = HashMap.unionWithKey
--unionsWith = HashMap.unionsWith
--mapWithKey = HashMap.mapWithKey
--mapKeysWith = HashMap.mapKeysWith
instance IsMap (IntMap.IntMap value) where
type MapValue (IntMap.IntMap value) = value
lookup = IntMap.lookup
{-# INLINE lookup #-}
insertMap = IntMap.insert
{-# INLINE insertMap #-}
deleteMap = IntMap.delete
{-# INLINE deleteMap #-}
singletonMap = IntMap.singleton
{-# INLINE singletonMap #-}
mapFromList = IntMap.fromList
{-# INLINE mapFromList #-}
mapToList = IntMap.toList
{-# INLINE mapToList #-}
findWithDefault = IntMap.findWithDefault
{-# INLINE findWithDefault #-}
insertWith = IntMap.insertWith
{-# INLINE insertWith #-}
insertWithKey = IntMap.insertWithKey
{-# INLINE insertWithKey #-}
insertLookupWithKey = IntMap.insertLookupWithKey
{-# INLINE insertLookupWithKey #-}
adjustMap = IntMap.adjust
{-# INLINE adjustMap #-}
adjustWithKey = IntMap.adjustWithKey
{-# INLINE adjustWithKey #-}
updateMap = IntMap.update
{-# INLINE updateMap #-}
updateWithKey = IntMap.updateWithKey
{-# INLINE updateWithKey #-}
--updateLookupWithKey = IntMap.updateLookupWithKey
alterMap = IntMap.alter
{-# INLINE alterMap #-}
unionWith = IntMap.unionWith
{-# INLINE unionWith #-}
unionWithKey = IntMap.unionWithKey
{-# INLINE unionWithKey #-}
unionsWith = IntMap.unionsWith
{-# INLINE unionsWith #-}
mapWithKey = IntMap.mapWithKey
{-# INLINE mapWithKey #-}
#if MIN_VERSION_containers(0, 5, 0)
mapKeysWith = IntMap.mapKeysWith
{-# INLINE mapKeysWith #-}
#endif
instance Eq key => IsMap [(key, value)] where
type MapValue [(key, value)] = value
lookup = List.lookup
{-# INLINE lookup #-}
insertMap k v = ((k, v):) . deleteMap k
{-# INLINE insertMap #-}
deleteMap k = List.filter ((/= k) . fst)
{-# INLINE deleteMap #-}
singletonMap k v = [(k, v)]
{-# INLINE singletonMap #-}
mapFromList = id
{-# INLINE mapFromList #-}
mapToList = id
{-# INLINE mapToList #-}
class (SetContainer set, Element set ~ ContainerKey set) => IsSet set where
insertSet :: Element set -> set -> set
deleteSet :: Element set -> set -> set
singletonSet :: Element set -> set
setFromList :: [Element set] -> set
setToList :: set -> [Element set]
instance Ord element => IsSet (Set.Set element) where
insertSet = Set.insert
{-# INLINE insertSet #-}
deleteSet = Set.delete
{-# INLINE deleteSet #-}
singletonSet = Set.singleton
{-# INLINE singletonSet #-}
setFromList = Set.fromList
{-# INLINE setFromList #-}
setToList = Set.toList
{-# INLINE setToList #-}
instance (Eq element, Hashable element) => IsSet (HashSet.HashSet element) where
insertSet = HashSet.insert
{-# INLINE insertSet #-}
deleteSet = HashSet.delete
{-# INLINE deleteSet #-}
singletonSet = HashSet.singleton
{-# INLINE singletonSet #-}
setFromList = HashSet.fromList
{-# INLINE setFromList #-}
setToList = HashSet.toList
{-# INLINE setToList #-}
instance IsSet IntSet.IntSet where
insertSet = IntSet.insert
{-# INLINE insertSet #-}
deleteSet = IntSet.delete
{-# INLINE deleteSet #-}
singletonSet = IntSet.singleton
{-# INLINE singletonSet #-}
setFromList = IntSet.fromList
{-# INLINE setFromList #-}
setToList = IntSet.toList
{-# INLINE setToList #-}
-- | zip operations on MonoFunctors.
class MonoFunctor mono => MonoZip mono where
ozipWith :: (Element mono -> Element mono -> Element mono) -> mono -> mono -> mono
ozip :: mono -> mono -> [(Element mono, Element mono)]
ounzip :: [(Element mono, Element mono)] -> (mono, mono)
instance MonoZip ByteString.ByteString where
ozip = ByteString.zip
ounzip = ByteString.unzip
ozipWith f xs = ByteString.pack . ByteString.zipWith f xs
{-# INLINE ozip #-}
{-# INLINE ounzip #-}
{-# INLINE ozipWith #-}
instance MonoZip LByteString.ByteString where
ozip = LByteString.zip
ounzip = LByteString.unzip
ozipWith f xs = LByteString.pack . LByteString.zipWith f xs
{-# INLINE ozip #-}
{-# INLINE ounzip #-}
{-# INLINE ozipWith #-}
instance MonoZip Text.Text where
ozip = Text.zip
ounzip = (Text.pack *** Text.pack) . List.unzip
ozipWith = Text.zipWith
{-# INLINE ozip #-}
{-# INLINE ounzip #-}
{-# INLINE ozipWith #-}
instance MonoZip LText.Text where
ozip = LText.zip
ounzip = (LText.pack *** LText.pack) . List.unzip
ozipWith = LText.zipWith
{-# INLINE ozip #-}
{-# INLINE ounzip #-}
{-# INLINE ozipWith #-}