---------------------------------------------------------------------- -- | -- Module : Assoc -- Maintainer : Peter Ljunglöf -- Stability : Stable -- Portability : Haskell 98 -- -- > CVS $Date: 2005/05/09 09:28:44 $ -- > CVS $Author: peb $ -- > CVS $Revision: 1.4 $ -- -- Association lists, or finite maps, -- including sets as maps with result type @()@. -- function names stolen from module @Array@. -- /O(log n)/ key lookup ----------------------------------------------------------------------------- module GF.Data.Assoc ( Assoc, Set, emptyAssoc, emptySet, listAssoc, listSet, accumAssoc, aAssocs, aElems, assocMap, assocFilter, lookupAssoc, lookupWith, (?), (?=) ) where import GF.Data.SortedList infixl 9 ?, ?= -- | a set is a finite map with empty values type Set a = Assoc a () emptyAssoc :: Ord a => Assoc a b emptySet :: Ord a => Set a -- | creating a finite map from a sorted key-value list listAssoc :: Ord a => SList (a, b) -> Assoc a b -- | creating a set from a sorted list listSet :: Ord a => SList a -> Set a -- | building a finite map from a list of keys and 'b's, -- and a function that combines a sorted list of 'b's into a value accumAssoc :: (Ord a, Ord c) => (SList c -> b) -> [(a, c)] -> Assoc a b -- | all key-value pairs from an association list aAssocs :: Ord a => Assoc a b -> SList (a, b) -- | all keys from an association list aElems :: Ord a => Assoc a b -> SList a -- fmap :: Ord a => (b -> b') -> Assoc a b -> Assoc a b' -- | mapping values to other values. -- the mapping function can take the key as information assocMap :: Ord a => (a -> b -> b') -> Assoc a b -> Assoc a b' assocFilter :: Ord a => (b -> Bool) -> Assoc a b -> Assoc a b assocFilter pred = listAssoc . filter (pred . snd) . aAssocs -- | monadic lookup function, -- returning failure if the key does not exist lookupAssoc :: (Ord a, Monad m) => Assoc a b -> a -> m b -- | if the key does not exist, -- the first argument is returned lookupWith :: Ord a => b -> Assoc a b -> a -> b -- | if the values are monadic, we can return the value type (?) :: (Ord a, Monad m) => Assoc a (m b) -> a -> m b -- | checking wheter the map contains a given key (?=) :: Ord a => Assoc a b -> a -> Bool ------------------------------------------------------------ data Assoc a b = ANil | ANode (Assoc a b) a b (Assoc a b) deriving (Eq, Ord, Show) emptyAssoc = ANil emptySet = emptyAssoc listAssoc as = assoc where (assoc, []) = sl2bst (length as) as sl2bst 0 xs = (ANil, xs) sl2bst 1 (x:xs) = (ANode ANil (fst x) (snd x) ANil, xs) sl2bst n xs = (ANode left (fst x) (snd x) right, zs) where llen = (n-1) `div` 2 rlen = n - 1 - llen (left, x:ys) = sl2bst llen xs (right, zs) = sl2bst rlen ys listSet as = listAssoc (zip as (repeat ())) accumAssoc join = listAssoc . map (mapSnd join) . groupPairs . nubsort where mapSnd f (a, b) = (a, f b) aAssocs as = prs as [] where prs ANil = id prs (ANode left a b right) = prs left . ((a,b) :) . prs right aElems = map fst . aAssocs instance Ord a => Functor (Assoc a) where fmap f = assocMap (const f) assocMap f ANil = ANil assocMap f (ANode left a b right) = ANode (assocMap f left) a (f a b) (assocMap f right) lookupAssoc ANil _ = fail "key not found" lookupAssoc (ANode left a b right) a' = case compare a a' of GT -> lookupAssoc left a' LT -> lookupAssoc right a' EQ -> return b lookupWith z ANil _ = z lookupWith z (ANode left a b right) a' = case compare a a' of GT -> lookupWith z left a' LT -> lookupWith z right a' EQ -> b (?) = lookupWith (fail "key not found") (?=) = \assoc -> maybe False (const True) . lookupAssoc assoc