@@ -9,6 +9,7 @@
9{-# LANGUAGE Rank2Types #-}
9{-# LANGUAGE Rank2Types #-}
10{-# LANGUAGE TypeFamilies #-}
10{-# LANGUAGE TypeFamilies #-}
11{-# LANGUAGE TypeInType #-}
11{-# LANGUAGE TypeInType #-}
12+{-# LANGUAGE ViewPatterns #-}
13-- {-# OPTIONS_GHC -ddump-simpl -dsuppress-idinfo -dsuppress-coercions -dsuppress-type-applications -dsuppress-uniques -dsuppress-module-prefixes #-}
14-- {-# OPTIONS_GHC -ddump-simpl -dsuppress-idinfo -dsuppress-coercions -dsuppress-type-applications -dsuppress-uniques -dsuppress-module-prefixes #-}
@@ -22,7 +23,6 @@ module Data.TypeRepMap.Internal where
23import Prelude hiding (lookup)
24import Prelude hiding (lookup)
25−import Control.Arrow ((&&&))
26import Data.Function (on)
26import Data.Function (on)
27import Data.IntMap.Strict (IntMap)
27import Data.IntMap.Strict (IntMap)
28import Data.Kind (Type)
28import Data.Kind (Type)
@@ -30,14 +30,14 @@ import Data.List (nubBy)
30import Data.Maybe (fromJust)
30import Data.Maybe (fromJust)
31import Data.Primitive.Array (Array, indexArray, mapArray')
31import Data.Primitive.Array (Array, indexArray, mapArray')
32import Data.Primitive.PrimArray (PrimArray, indexPrimArray, sizeofPrimArray)
32import Data.Primitive.PrimArray (PrimArray, indexPrimArray, sizeofPrimArray)
33−import Data.Proxy (Proxy (..))
34import Data.Semigroup (Semigroup (..))
33import Data.Semigroup (Semigroup (..))
35−import Data.Typeable (Typeable, typeRep, typeRepFingerprint)
36import GHC.Base (Any, Int (..), Int#, (*#), (+#), (<#))
34import GHC.Base (Any, Int (..), Int#, (*#), (+#), (<#))
37−import GHC.Exts (inline, sortWith)
35+import GHC.Exts (IsList (..), inline, sortWith)
38import GHC.Fingerprint (Fingerprint (..))
36import GHC.Fingerprint (Fingerprint (..))
39import GHC.Prim (eqWord#, ltWord#)
37import GHC.Prim (eqWord#, ltWord#)
40import GHC.Word (Word64 (..))
38import GHC.Word (Word64 (..))
39+import Type.Reflection (Typeable, typeRep, withTypeable)
40+import Type.Reflection.Unsafe (typeRepFingerprint)
41import Unsafe.Coerce (unsafeCoerce)
41import Unsafe.Coerce (unsafeCoerce)
43import qualified Data.IntMap.Strict as IM
43import qualified Data.IntMap.Strict as IM
@@ -70,6 +70,7 @@ data TypeRepMap (f :: k -> Type) =
70 { fingerprintAs :: {-# UNPACK #-} !(PrimArray Word64) -- ^ first components of key fingerprints
70 { fingerprintAs :: {-# UNPACK #-} !(PrimArray Word64) -- ^ first components of key fingerprints
71 , fingerprintBs :: {-# UNPACK #-} !(PrimArray Word64) -- ^ second components of key fingerprints
71 , fingerprintBs :: {-# UNPACK #-} !(PrimArray Word64) -- ^ second components of key fingerprints
72 , anys :: {-# UNPACK #-} !(Array Any) -- ^ values stored in the map
72 , anys :: {-# UNPACK #-} !(Array Any) -- ^ values stored in the map
73+ , keys :: {-# UNPACK #-} !(Array Any) -- ^ typerep keys
74 -- ^ an unsafe constructor for 'TypeRepMap'
75 -- ^ an unsafe constructor for 'TypeRepMap'
@@ -84,7 +85,7 @@ instance Semigroup (TypeRepMap f) where
84 {-# INLINE (<>) #-}
85 {-# INLINE (<>) #-}
86instance Monoid (TypeRepMap f) where
87instance Monoid (TypeRepMap f) where
87− mempty = TypeRepMap mempty mempty mempty
88+ mempty = TypeRepMap mempty mempty mempty mempty
88 mappend = (<>)
89 mappend = (<>)
89 {-# INLINE mempty #-}
90 {-# INLINE mempty #-}
90 {-# INLINE mappend #-}
91 {-# INLINE mappend #-}
@@ -127,13 +128,13 @@ prop> member @a (insert (x :: f a) tm) == True
129insert :: forall a f . Typeable a => f a -> TypeRepMap f -> TypeRepMap f
130insert :: forall a f . Typeable a => f a -> TypeRepMap f -> TypeRepMap f
130−insert x = fromListPairs . addX . toPairList
131+insert x = fromTriples . addX . toTriples
132− pairX :: (Fingerprint, Any)
133+ tripleX :: (Fingerprint, Any, Any)
133− pairX@(fpX, _) = (calcFp x, toAny x)
134+ tripleX@(fpX, _, _) = (calcFp @a, toAny x, unsafeCoerce $ typeRep @a)
135− addX :: [(Fingerprint, Any)] -> [(Fingerprint, Any)]
136+ addX :: [(Fingerprint, Any, Any)] -> [(Fingerprint, Any, Any)]
136− addX l = pairX : deleteByFst fpX l
137+ addX l = tripleX : deleteByFst fpX l
137{-# INLINE insert #-}
138{-# INLINE insert #-}
139-- Extract the kind of a type. We use it to work around lack of syntax for
140-- Extract the kind of a type. We use it to work around lack of syntax for
@@ -154,7 +155,7 @@ False
156delete :: forall a (f :: KindOf a -> Type) . Typeable a => TypeRepMap f -> TypeRepMap f
157delete :: forall a (f :: KindOf a -> Type) . Typeable a => TypeRepMap f -> TypeRepMap f
157−delete = fromListPairs . deleteByFst (typeFp @a) . toPairList
158+delete = fromTriples . deleteByFst (typeFp @a) . toTriples
158{-# INLINE delete #-}
159{-# INLINE delete #-}
160{- | Map over the elements of a 'TypeRepMap'.
161{- | Map over the elements of a 'TypeRepMap'.
@@ -171,19 +172,30 @@ Just [True]
173hoist :: (forall x. f x -> g x) -> TypeRepMap f -> TypeRepMap g
174hoist :: (forall x. f x -> g x) -> TypeRepMap f -> TypeRepMap g
174−hoist f (TypeRepMap as bs ans) = TypeRepMap as bs $ mapArray' (toAny . f . fromAny) ans
175+hoist f (TypeRepMap as bs ans ks) = TypeRepMap as bs (mapArray' (toAny . f . fromAny) ans) ks
175{-# INLINE hoist #-}
176{-# INLINE hoist #-}
178+hoistA :: (Applicative t) => (forall x. f x -> t (g x)) -> TypeRepMap f -> t (TypeRepMap g)
179+hoistA f (TypeRepMap as bs (toList -> ans) ks) = (\l -> TypeRepMap as bs (fromList $ map toAny l) ks)
180+ <$> traverse (f . fromAny) ans
181+{-# INLINE hoistA #-}
177-- | The union of two 'TypeRepMap's using a combining function.
183-- | The union of two 'TypeRepMap's using a combining function.
178unionWith :: (forall x. f x -> f x -> f x) -> TypeRepMap f -> TypeRepMap f -> TypeRepMap f
184unionWith :: (forall x. f x -> f x -> f x) -> TypeRepMap f -> TypeRepMap f -> TypeRepMap f
179−unionWith f m1 m2 = fromListPairs
185+unionWith f m1 m2 = fromTriples
180− $ Map.toList
186+ $ toTripleList
181 $ Map.unionWith combine
187 $ Map.unionWith combine
182− (Map.fromList $ toPairList m1)
188+ (fromTripleList $ toTriples m1)
183− (Map.fromList $ toPairList m2)
189+ (fromTripleList $ toTriples m2)
185− combine :: Any -> Any -> Any
191+ combine :: (Any, Any) -> (Any, Any) -> (Any, Any)
186− combine a b = toAny $ f (fromAny a) (fromAny b)
192+ combine (av, ak) (bv, _) = (toAny $ f (fromAny av) (fromAny bv), ak)
194+ fromTripleList :: Ord a => [(a, b, c)] -> Map.Map a (b, c)
195+ fromTripleList = Map.fromList . map (\(a, b, c) -> (a, (b, c)))
197+ toTripleList :: Map.Map a (b, c) -> [(a, b, c)]
198+ toTripleList = map (\(a, (b, c)) -> (a, b, c)) . Map.toList
187{-# INLINE unionWith #-}
199{-# INLINE unionWith #-}
189-- | The (left-biased) union of two 'TypeRepMap's. It prefers the first map when
201-- | The (left-biased) union of two 'TypeRepMap's. It prefers the first map when
@@ -259,56 +271,73 @@ fromAny :: Any -> f a
259fromAny = unsafeCoerce
271fromAny = unsafeCoerce
261typeFp :: forall a . Typeable a => Fingerprint
273typeFp :: forall a . Typeable a => Fingerprint
262−typeFp = typeRepFingerprint $ typeRep $ Proxy @a
274+typeFp = typeRepFingerprint $ typeRep @a
263{-# INLINE typeFp #-}
275{-# INLINE typeFp #-}
265−toPairList :: TypeRepMap f -> [(Fingerprint, Any)]
277+toTriples :: TypeRepMap f -> [(Fingerprint, Any, Any)]
266−toPairList tm = zip (toFingerprints tm) (GHC.toList $ anys tm)
278+toTriples tm = zip3 (toFingerprints tm) (GHC.toList $ anys tm) (GHC.toList $ keys tm)
268−deleteByFst :: Eq a => a -> [(a, b)] -> [(a, b)]
280+deleteByFst :: Eq a => a -> [(a, b, c)] -> [(a, b, c)]
269−deleteByFst x = filter ((/= x) . fst)
281+deleteByFst x = filter ((/= x) . fst3)
271−nubByFst :: (Eq a) => [(a, b)] -> [(a, b)]
283+nubByFst :: (Eq a) => [(a, b, c)] -> [(a, b, c)]
272−nubByFst = nubBy ((==) `on` fst)
284+nubByFst = nubBy ((==) `on` fst3)
286+fst3 :: (a, b, c) -> a
274----------------------------------------------------------------------------
289----------------------------------------------------------------------------
275-- Functions for testing and benchmarking
290-- Functions for testing and benchmarking
276----------------------------------------------------------------------------
291----------------------------------------------------------------------------
278-- | Existential wrapper around 'Typeable' indexed by @f@ type parameter.
293-- | Existential wrapper around 'Typeable' indexed by @f@ type parameter.
279−-- Useful for 'TypeRepMap' structure creation form list of 'TF's.
294+-- Useful for 'TypeRepMap' structure creation form list of 'WrapTypeable's.
280−data TF f where
295+data WrapTypeable f where
281− TF :: Typeable a => f a -> TF f
296+ WrapTypeable :: Typeable a => f a -> WrapTypeable f
298+instance Show (WrapTypeable f) where
299+ show (WrapTypeable (_ :: f a)) = show $ calcFp @a
283−instance Show (TF f) where
301+{- |
284− show (TF tf) = show $ calcFp tf
286−{- | Creates 'TypeRepMap' from a list of 'TF's.
303+prop> fromList . toList == 'id'
305+Creates 'TypeRepMap' from a list of 'WrapTypeable's.
288−>>> size $ fromList [TF $ Identity True, TF $ Identity 'a']
307+>>> size $ fromList [WrapTypeable $ Identity True, WrapTypeable $ Identity 'a']
292−fromList :: forall f . [TF f] -> TypeRepMap f
312+instance IsList (TypeRepMap f) where
313+ type Item (TypeRepMap f) = WrapTypeable f
315+ fromList :: [WrapTypeable f] -> TypeRepMap f
293−fromList = fromListPairs . map (fp &&& an)
316+ fromList = fromTriples . map (\x -> (fp x, an x, k x))
295− fp :: TF f -> Fingerprint
318+ fp :: WrapTypeable f -> Fingerprint
296− fp (TF x) = calcFp x
319+ fp (WrapTypeable (_ :: f a)) = calcFp @a
321+ an :: WrapTypeable f -> Any
322+ an (WrapTypeable x) = toAny x
298− an :: TF f -> Any
324+ k :: WrapTypeable f -> Any
299− an (TF x) = toAny x
325+ k (WrapTypeable (_ :: f a)) = unsafeCoerce $ typeRep @a
301−fromF :: Typeable a => f a -> Proxy a
327+ toList :: TypeRepMap f -> [WrapTypeable f]
302−fromF _ = Proxy
328+ toList = map toWrapTypeable . toTriples
330+ toWrapTypeable :: (Fingerprint, Any, Any) -> WrapTypeable f
331+ toWrapTypeable (_, an, k) = withTypeable (unsafeCoerce k) $ fromAny an
304−calcFp :: Typeable a => f a -> Fingerprint
333+calcFp :: forall a . Typeable a => Fingerprint
305−calcFp = typeRepFingerprint . typeRep . fromF
334+calcFp = typeRepFingerprint $ typeRep @a
307−fromListPairs :: [(Fingerprint, Any)] -> TypeRepMap f
336+fromTriples :: [(Fingerprint, Any, Any)] -> TypeRepMap f
308−fromListPairs kvs = TypeRepMap (GHC.fromList fpAs) (GHC.fromList fpBs) (GHC.fromList ans)
337+fromTriples kvs = TypeRepMap (GHC.fromList fpAs) (GHC.fromList fpBs) (GHC.fromList ans) (GHC.fromList ks)
310 (fpAs, fpBs) = unzip $ map (\(Fingerprint a b) -> (a, b)) fps
339 (fpAs, fpBs) = unzip $ map (\(Fingerprint a b) -> (a, b)) fps
311− (fps, ans) = unzip $ fromSortedList $ sortWith fst $ nubByFst kvs
340+ (fps, ans, ks) = unzip3 $ fromSortedList $ sortWith fst3 $ nubByFst kvs
313----------------------------------------------------------------------------
342----------------------------------------------------------------------------
314-- Tree-like conversion
343-- Tree-like conversion