{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE DeriveDataTypeable #-}
{- |
Data.Map with multiple, unique keys.
IxSet without the Sets.
> module Main where
>
> import Data.Map.MultiKey
> import Data.Typeable
> import Prelude hiding (lookup, null)
>
> data Record = Record
> { rIntKey :: Int
> , rStringKey :: String
> , rData :: String
> } deriving (Show, Typeable)
>
> instance MultiKeyable Record where
> empty = MultiKey [key rIntKey, key rStringKey]
>
> records :: [Record]
> records =
> [ Record 1 "key 1" "data 1"
> , Record 20 "key 20" "data 20"
> , Record 3 "key 3" "data 3"
> ]
>
> mk :: MultiKey Record
> mk = fromList records
> > lookup (1::Int) mk
> Just (Record {rIntKey = 1, rStringKey = "key 1", rData = "data 1"})
> it :: Maybe Record
> > lookup "key 20" mk
> Just (Record {rIntKey = 20, rStringKey = "key 20", rData = "data 20"})
> it :: Maybe Record
> > lookup 2.0 mk
> *** Exception: MultiKey: there is no key of type Double in MultiKey Record
-}
module Data.Map.MultiKey
( MultiKey(..)
, MultiKeyable(..)
, delete
, deleteKey
, fromList
, insert
, insertList
, key
, lookup
, null
, toList
, updateKey
) where
import Data.List (foldl')
import Data.Map (Map)
import qualified Data.Map as M
import Data.Typeable
import Prelude hiding (lookup, null)
data Key a = forall k . (Typeable k, Ord k) =>
Key (Map k a) (a -> k) deriving Typeable
data MultiKey a = MultiKey [Key a] deriving Typeable
class MultiKeyable a where
empty :: MultiKey a
key :: (Typeable k, Ord k) => (a -> k) -> Key a
key f = Key M.empty f
lookup :: (Typeable a, Typeable k) => k -> MultiKey a -> Maybe a
lookup k mk@(MultiKey keys) = lookup' keys
where
lookup' [] = error $ "MultiKey: there is no key of type "
++ (show $ typeOf k) ++ " in " ++ (show $ typeOf mk)
lookup' (Key m _:ks) = maybe (lookup' ks) (`M.lookup` m) $ cast k
insertIntoKey :: a -> Key a -> Key a
insertIntoKey x (Key m getIdx) = Key (M.insert (getIdx x) x m) getIdx
insert :: a -> MultiKey a -> MultiKey a
insert x (MultiKey indexes) = MultiKey $ map (insertIntoKey x) indexes
insertList :: MultiKeyable a => [a] -> MultiKey a -> MultiKey a
insertList xs (MultiKey keys) = MultiKey $ map f keys
where
f key = foldl' (flip insertIntoKey) key xs
deleteFromKey :: a -> Key a -> Key a
deleteFromKey x (Key m getIdx) = Key (M.delete (getIdx x) m) getIdx
delete :: a -> MultiKey a -> MultiKey a
delete x (MultiKey indexes) = MultiKey $ map (deleteFromKey x) indexes
updateKey :: (Typeable a, Typeable k) => k -> a -> MultiKey a -> MultiKey a
updateKey k v mk = insert v $ maybe mk (flip delete mk) $ lookup k mk
deleteKey :: (Typeable a, Typeable k) => k -> MultiKey a -> MultiKey a
deleteKey k mim = maybe mim (flip delete mim) $ lookup k mim
null :: MultiKey a -> Bool
null (MultiKey (Key m _:_)) = M.null m
null (MultiKey []) = True
fromList :: MultiKeyable a => [a] -> MultiKey a
fromList = flip insertList empty
toList :: MultiKey a -> [a]
toList (MultiKey []) = []
toList (MultiKey (Key m _:_)) = M.elems m