    module Data.TypeMap(
        TypeMap, empty,
        lookup, insert, find
        ) where

    import Prelude hiding (lookup)
    import Control.Monad
    import Data.Dynamic
    import Data.Maybe
    import qualified Data.Map as Map

    newtype TypeMap = TypeMap (Map.Map TypeRep Dynamic)

    empty :: TypeMap
    empty = TypeMap Map.empty

    lookup :: Typeable a => TypeMap -> Maybe a
    lookup (TypeMap mp) = res
        where res = liftM (fromJust . fromDynamic) $ Map.lookup (typeOf $ fromJust res) mp

    find :: Typeable a => TypeMap -> a
    find mp = res
        where res = fromMaybe (error msg) $ lookup mp
              msg = "Data.TypeMap.find, couldn't find " ++ show (typeOf res)

    insert :: Typeable a => a -> TypeMap -> TypeMap
    insert a (TypeMap mp) = TypeMap $ Map.insert (typeOf a) (toDyn a) mp

    instance Ord TypeRep where
        compare a b = compare (splitTyConApp a) (splitTyConApp b)

    instance Ord TyCon where
        compare a b = compare (tyConString a) (tyConString b)