module Control.Monad.TagShare(
DynMap,
dynEmpty,
dynInsert,
dynLookup,
Sharing,
runSharing,
share
) where
import Control.Monad.State
import Data.Typeable
import Data.Dynamic(Dynamic, fromDynamic, toDyn)
import Data.Map as M
newtype DynMap tag =
DynMap (M.Map (tag, TypeRep) Dynamic)
deriving Show
dynEmpty :: DynMap tag
dynEmpty = DynMap M.empty
dynInsert :: (Typeable a, Ord tag) =>
tag -> a -> DynMap tag -> DynMap tag
dynInsert u a (DynMap m) =
DynMap (M.insert (u,typeOf a) (toDyn a) m)
dynLookup :: (Typeable a, Ord tag) =>
tag -> DynMap tag -> Maybe a
dynLookup u (DynMap m) = hlp fun undefined where
hlp :: Typeable a =>
(TypeRep -> Maybe a) -> a -> Maybe a
hlp f a = f (typeOf a)
fun tr = M.lookup (u,tr) m >>= fromDynamic
type Sharing tag a = State (DynMap tag) a
runSharing :: Sharing tag a -> a
runSharing m = evalState m dynEmpty
share :: (Typeable a, Ord tag) =>
tag -> Sharing tag a -> Sharing tag a
share t m = do
mx <- gets $ (dynLookup t)
case mx of
Just e -> return e
Nothing -> mfix $ \e -> do
modify (dynInsert t e)
m