------------------------------------------------------------------------------ -- | -- Maintainer : Ralf Laemmel, Joost Visser -- Stability : experimental -- Portability : portable -- -- This module is part of 'StrategyLib', a library of functional strategy -- combinators, including combinators for generic traversal. This module -- provides combinators which allow one to use strategies to construct -- generic containers. ------------------------------------------------------------------------------ module ContainerTheme ( module ContainerTheme, ) where import StrategyPrelude import Control.Monad import Data.Monoid ------------------------------------------------------------------------------ -- * Pointwise function update -- | Pointwise modification of monomorphic functions modify :: Eq x => (x -> y) -> x -> y -> (x -> y) modify f x y = \x' -> if x == x' then y else f x' -- | Pointwise modification of type-preserving strategies modifyTP :: (MonadPlus m, Eq t, Term t) => TP m -> t -> m t -> TP m modifyTP f t = adhocTP f . modify (applyTP f) t -- | Pointwise modification of type-unifying strategies modifyTU :: (MonadPlus m, Eq t, Term t) => TU a m -> t -> m a -> TU a m modifyTU f t = adhocTU f . modify (applyTU f) t ------------------------------------------------------------------------------ -- * Generic Set (not observable) -- | Type of generic sets type GSet = TU () Maybe -- | Empty generic set. emptyGSet :: GSet emptyGSet = failTU -- | Completely filled generic set fullGSet :: GSet fullGSet = constTU mempty -- | Add an element to a generic set addGSet :: (Eq t, Term t) => t -> GSet -> GSet addGSet t s = modifyTU s t (return mempty) -- | Remove an element from a generic set removeGSet :: (Eq t, Term t) => t -> GSet -> GSet removeGSet t s = modifyTU s t mzero -- | Test whether a given element is contained in a generic set containsGSet :: (Eq t, Term t) => t -> GSet -> Bool containsGSet t s= maybe False (const True) (applyTU s t) ------------------------------------------------------------------------------ -- * Generic Map (not observable) -- | Type of generic maps type GMap value = TU value Maybe -- | Empty generic map emptyGMap :: GMap v emptyGMap = failTU -- | Remove an element from a generic map (my key) removeGMap :: (Eq t, Term t) => t -> GMap v -> GMap v removeGMap t s = modifyTU s t mzero -- | Test whether an element with given key is contained in a generic map containsGMap :: (Eq t, Term t) => t -> GMap v -> Bool containsGMap t s= maybe False (const True) (applyTU s t) -- | Add an entry with given key and value to a generic map putGMap :: (Eq t, Term t) => t -> v -> GMap v -> GMap v putGMap t v s = modifyTU s t (return v) -- | Obtain the value for a given key from a generic map getGMap :: (Eq t, Term t) => t -> GMap v -> Maybe v getGMap t s = applyTU s t ------------------------------------------------------------------------------ --- Generic List (observable per type) --------------------------------------- type GList = (Integer -> TP Maybe,Integer) sizeGList (_,i) = i indxGList (f,_) = f emptyGList :: GList emptyGList = (const failTP,0) addGList :: Term t => t -> GList -> GList addGList t l = (modify f s e,s+1) where s = sizeGList l f = indxGList l e = monoTP (const (return t)) putGList :: Term t => Integer -> t -> GList -> GList putGList i t l = if i < s then (modify f i e,s) else l where s = sizeGList l f = indxGList l e = monoTP (const (return t)) getGList :: Term t => Integer -> GList -> Maybe t getGList i l = if i < s then applyTP (f i) undefined else Nothing where f = indxGList l s = sizeGList l mapGListTP :: TP Maybe -> GList -> GList mapGListTP s l = (nth (map forElem [0..size-1]),size) where forElem :: Integer -> TP Maybe forElem i = (indxGList l i) `seqTP` s size = sizeGList l mapGListTU :: Term t => (t -> ()) -> TU a Maybe -> GList -> [Maybe a] mapGListTU g s l= map forElem [0..size-1] where forElem i = applyTU ((indxGList l i) `seqTU` s) t size = sizeGList l (t,()) = (undefined,g t) elemsGList :: Term t => (t -> ()) -> GList -> [t] elemsGList g l = filterJust (map forElem [0..size-1]) where forElem i = applyTP (indxGList l i) t size = sizeGList l (t,()) = (error "NOTERM",g t) filterJust as = map unJust (filter isJust as) unJust (Just t) = t isJust (Just _) = True isJust Nothing = False -- Variation on !! but now for Integer iso Int nth :: [a] -> Integer -> a nth (x:_) 0 = x nth (_:xs) n | n>0 = nth xs (n-1) nth (_:_) _ = error "ContainterTheme.nth: negative index" nth [] _ = error "ContainerTheme.nth: index too large" ------------------------------------------------------------------------------ --- Assign unique codes to terms of any type --------------------------------- type Coder = (Int,TU Int Maybe) noCode :: Coder noCode = (0,failTU) getCode :: Term x => Coder -> x -> Maybe Int getCode (_,s) = applyTU s setCode :: (Term x, Eq x) => Coder -> x -> Int -> Coder setCode (i,s) x i' = (i,modifyTU s x (return i')) nextCode :: Coder -> (Int,Coder) nextCode (i,s) = (i,(i+1,s)) enCode :: (Term x, Eq x) => Coder -> x -> Coder enCode c x = maybe gen found (getCode c x) where gen = let (i,c') = nextCode c in setCode c' x i found = const c ------------------------------------------------------------------------------