Skip to content

Instantly share code, notes, and snippets.

@Cedev
Created September 15, 2015 03:00
Show Gist options
  • Save Cedev/83162cdfe4dfff6b0d63 to your computer and use it in GitHub Desktop.
Save Cedev/83162cdfe4dfff6b0d63 to your computer and use it in GitHub Desktop.
A map from types to values indexed by those types
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RankNTypes #-}
module Data.TypeMap (
TypeMap (),
null,
size,
member,
notMember,
lookup,
findWithDefault,
empty,
singleton,
insert,
insertWith,
delete,
adjust,
update,
alter,
union,
unionWith,
unions,
unionsWith,
difference,
differenceWith,
intersection,
intersectionWith,
mergeWithKey,
map,
traverseWithKey,
foldr,
foldl,
foldMapWithKey,
elems,
filter,
partition,
mapMaybe,
mapEither
) where
import Prelude hiding (null, lookup, map, foldl, foldr, filter, partition)
import Control.Applicative ((<|>), Applicative)
import Control.Arrow ((***))
import Data.Functor
import qualified Data.Map as Map
import Data.Maybe hiding (mapMaybe)
import Data.Monoid
import Data.Proxy
import Data.Typeable
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(.:) f g a b = f $ g a b
data GDynamic f where
GDynamic :: Typeable a => f a -> GDynamic f
unGDynamic :: Typeable a => GDynamic f -> Maybe (f a)
unGDynamic (GDynamic f) = gcast f
fromGDynamic :: (forall a. Typeable a => f a -> b) -> GDynamic f -> b
fromGDynamic f (GDynamic fa) = f fa
mapGDynamic :: (forall a. Typeable a => f a -> g a) -> GDynamic f -> GDynamic g
mapGDynamic f (GDynamic fa) = GDynamic (f fa)
traverseGDynamic :: Functor m => (forall a. Typeable a => f a -> m (g a)) -> GDynamic f -> m (GDynamic g)
traverseGDynamic k (GDynamic fa) = fmap GDynamic . k $ fa
eitherGDynamic :: (forall a. Typeable a => f a -> Either (g a) (h a)) -> GDynamic f -> Either (GDynamic g) (GDynamic h)
eitherGDynamic k (GDynamic fa) = either (Left . GDynamic) (Right . GDynamic) (k fa)
-- You'd better know the GDynamic holds an f a
unsafeFromGDynamic :: Typeable a => GDynamic f -> f a
unsafeFromGDynamic = fromJust . unGDynamic
unsafeMapGDynamic :: (Typeable a, Typeable b) => (f a -> g b) -> GDynamic f -> GDynamic g
unsafeMapGDynamic f = GDynamic . f . unsafeFromGDynamic
unsafeLiftGDynamic2 :: (Typeable a, Typeable b, Typeable c) => (f a -> g b -> h c) -> GDynamic f -> GDynamic g -> GDynamic h
unsafeLiftGDynamic2 f a b = GDynamic $ f (unsafeFromGDynamic a) (unsafeFromGDynamic b)
unsafeTraverseGDynamic :: (Typeable a, Typeable b, Functor m) => (f a -> m (g b)) -> GDynamic f -> m (GDynamic g)
unsafeTraverseGDynamic k = fmap GDynamic . k . unsafeFromGDynamic
unsafeMapMGDynamic :: (Typeable a, Typeable b, Functor m, Functor n) => (m (f a) -> n (g b)) -> m (GDynamic f) -> n (GDynamic g)
unsafeMapMGDynamic k = fmap GDynamic . k . fmap unsafeFromGDynamic
unsafeFromGDynamic2 :: (forall a. Typeable a => f a -> g a -> c) -> GDynamic f -> GDynamic g -> c
unsafeFromGDynamic2 f (GDynamic fa) (GDynamic ga) = fromJust $ f fa <$> gcast ga
unsafeLiftGDynamic2' :: (forall a. Typeable a => f a -> g a -> h a) -> GDynamic f -> GDynamic g -> GDynamic h
unsafeLiftGDynamic2' f = unsafeFromGDynamic2 (GDynamic .: f)
unsafeTraverseGDynamic2 :: Functor m => (forall a. Typeable a => f a -> g a -> m (h a)) -> GDynamic f -> GDynamic g -> m (GDynamic h)
unsafeTraverseGDynamic2 f = unsafeFromGDynamic2 (fmap GDynamic .: f)
newtype TypeMap f = TypeMap {unTypeMap :: Map.Map TypeRep (GDynamic f)}
(!) :: Typeable a => TypeMap f -> p a -> f a
m ! p = unsafeFromGDynamic $ unTypeMap m Map.! typeRep p
(\\) :: TypeMap f -> TypeMap g -> TypeMap f
f \\ g = TypeMap $ unTypeMap f Map.\\ unTypeMap g
null :: TypeMap f -> Bool
null = Map.null . unTypeMap
size :: TypeMap f -> Int
size = Map.size . unTypeMap
member :: Typeable a => p a -> TypeMap f -> Bool
member k = Map.member (typeRep k) . unTypeMap
notMember :: Typeable a => p a -> TypeMap f -> Bool
notMember k = Map.notMember (typeRep k) . unTypeMap
lookup :: forall f a. Typeable a => TypeMap f -> Maybe (f a)
lookup = (>>= unGDynamic) . Map.lookup (typeRep (Proxy :: Proxy a)) . unTypeMap
findWithDefault :: Typeable a => f a -> TypeMap f -> f a
findWithDefault d = maybe d id . lookup
empty :: TypeMap f
empty = TypeMap $ Map.empty
singleton :: forall f a. Typeable a => f a -> TypeMap f
singleton = TypeMap . Map.singleton (typeRep (Proxy :: Proxy a)) . GDynamic
insert :: forall f a. Typeable a => f a -> TypeMap f -> TypeMap f
insert v = TypeMap . Map.insert (typeRep (Proxy :: Proxy a)) (GDynamic v) . unTypeMap
insertWith :: forall f a. Typeable a => (f a -> f a -> f a) -> f a -> TypeMap f -> TypeMap f
insertWith f v = TypeMap . Map.insertWith (unsafeLiftGDynamic2 f) (typeRep (Proxy :: Proxy a)) (GDynamic v) . unTypeMap
delete :: Typeable a => p a -> TypeMap f -> TypeMap f
delete p = TypeMap . Map.delete (typeRep p) . unTypeMap
adjust :: forall f a. Typeable a => (f a -> f a) -> TypeMap f -> TypeMap f
adjust f = TypeMap . Map.adjust (unsafeMapGDynamic f) (typeRep (Proxy :: Proxy a)) . unTypeMap
update :: forall f a. Typeable a => (f a -> Maybe (f a)) -> TypeMap f -> TypeMap f
update f = TypeMap . Map.update (unsafeTraverseGDynamic f) (typeRep (Proxy :: Proxy a)) . unTypeMap
alter :: forall f a. Typeable a => (Maybe (f a) -> Maybe (f a)) -> TypeMap f -> TypeMap f
alter f = TypeMap . Map.alter (unsafeMapMGDynamic f) (typeRep (Proxy :: Proxy a)) . unTypeMap
union :: TypeMap f -> TypeMap f -> TypeMap f
union a b = TypeMap $ Map.union (unTypeMap a) (unTypeMap b)
unionWith :: (forall a. Typeable a => f a -> f a -> f a) -> TypeMap f -> TypeMap f -> TypeMap f
unionWith f a b = TypeMap $ Map.unionWith (unsafeLiftGDynamic2' f) (unTypeMap a) (unTypeMap b)
unions :: [TypeMap f] -> TypeMap f
unions = TypeMap . Map.unions . fmap unTypeMap
unionsWith :: (forall a. Typeable a => f a -> f a -> f a) -> [TypeMap f] -> TypeMap f
unionsWith f = TypeMap . Map.unionsWith (unsafeLiftGDynamic2' f) . fmap unTypeMap
difference :: TypeMap f -> TypeMap g -> TypeMap f
difference a b = TypeMap $ Map.difference (unTypeMap a) (unTypeMap b)
differenceWith :: (forall a. Typeable a => f a -> g a -> h a) -> TypeMap f -> TypeMap g -> TypeMap h
differenceWith f a b = TypeMap $ Map.intersectionWith (unsafeLiftGDynamic2' f) (unTypeMap a) (unTypeMap b)
intersection :: TypeMap f -> TypeMap g -> TypeMap f
intersection a b = TypeMap $ Map.intersection (unTypeMap a) (unTypeMap b)
intersectionWith :: (forall a. Typeable a => f a -> g a -> h a) -> TypeMap f -> TypeMap g -> TypeMap h
intersectionWith f a b = TypeMap $ Map.intersectionWith (unsafeLiftGDynamic2' f) (unTypeMap a) (unTypeMap b)
mergeWithKey :: (forall a. Typeable a => f a -> g a -> Maybe (h a)) -> (TypeMap f -> TypeMap h) -> (TypeMap g -> TypeMap h) -> TypeMap f -> TypeMap g -> TypeMap h
mergeWithKey f ff fh a b = TypeMap $ Map.mergeWithKey (const $ unsafeTraverseGDynamic2 f) (unTypeMap . ff . TypeMap) (unTypeMap . fh . TypeMap) (unTypeMap a) (unTypeMap b)
map :: (forall a. Typeable a => f a -> g a) -> TypeMap f -> TypeMap g
map f = TypeMap . Map.map (mapGDynamic f) . unTypeMap
traverseWithKey :: Applicative t => (forall a. Typeable a => f a -> t (g a)) -> TypeMap f -> t (TypeMap g)
traverseWithKey f = fmap TypeMap . Map.traverseWithKey (const $ traverseGDynamic f) . unTypeMap
foldr :: (forall a. Typeable a => f a -> b -> b) -> b -> TypeMap f -> b
foldr f z = Map.foldr (fromGDynamic f) z . unTypeMap
foldl :: (forall a. Typeable a => b -> f a -> b) -> b -> TypeMap f -> b
foldl f z = Map.foldl (flip (fromGDynamic (flip f))) z . unTypeMap
foldMapWithKey :: Monoid m => (forall a. Typeable a => f a -> m) -> TypeMap f -> m
foldMapWithKey f = Map.foldMapWithKey (const $ fromGDynamic f) . unTypeMap
elems :: (forall a. Typeable a => f a -> b) -> TypeMap f -> [b]
elems f = fmap (fromGDynamic f) . Map.elems . unTypeMap
filter :: (forall a. Typeable a => f a -> Bool) -> TypeMap f -> TypeMap f
filter f = TypeMap . Map.filter (fromGDynamic f) . unTypeMap
partition :: (forall a. Typeable a => f a -> Bool) -> TypeMap f -> (TypeMap f, TypeMap f)
partition f = (TypeMap *** TypeMap) . Map.partition (fromGDynamic f) . unTypeMap
mapMaybe :: (forall a. Typeable a => f a -> Maybe (g a)) -> TypeMap f -> TypeMap g
mapMaybe f = TypeMap . Map.mapMaybe (traverseGDynamic f) . unTypeMap
mapEither :: (forall a. Typeable a => f a -> Either (g a) (h a)) -> TypeMap f -> (TypeMap g, TypeMap h)
mapEither f = (TypeMap *** TypeMap) . Map.mapEither (eitherGDynamic f) . unTypeMap
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment