@@ -205,6 +205,8 @@ insert x m
205-- inferred type variables (which are not subject to type applications).
205-- inferred type variables (which are not subject to type applications).
206type KindOf (a :: k) = k
206type KindOf (a :: k) = k
208+type ArgKindOf (f :: k -> l) = k
208{- | Delete a value from a 'TypeRepMap'.
210{- | Delete a value from a 'TypeRepMap'.
210TypeRepMap optimizes for fast reads rather than modifications, as a trade-off deletes are
212TypeRepMap optimizes for fast reads rather than modifications, as a trade-off deletes are
@@ -350,6 +352,48 @@ union :: TypeRepMap f -> TypeRepMap f -> TypeRepMap f
350union = unionWith const
352union = unionWith const
351{-# INLINE union #-}
353{-# INLINE union #-}
355+-- | The 'intersection' of two 'TypeRepMap's using a combining function
358+intersectionWith :: forall f. (forall x. Typeable x => f x -> f x -> f x) -> TypeRepMap f -> TypeRepMap f -> TypeRepMap f
359+intersectionWith f ma mb =
360+ fromSortedTriples $ mergeMaps (toSortedTriples ma) (toSortedTriples mb)
362+ f' :: forall x. TypeRep x -> f x -> f x -> f x
363+ f' tr = withTypeable tr f
365+ combine :: (Fingerprint, Any, Any) -> (Fingerprint, Any, Any) -> (Fingerprint, Any, Any)
366+ combine (fp, av, ak) (_, bv, _) = (fp, toAny $ f' (fromAny ak) (fromAny av) (fromAny bv), ak)
368+ -- Merges two typrepmaps into a sorted, dedup'd list of triples.
369+ mergeMaps :: [(Fingerprint, Any, Any)] -> [(Fingerprint, Any, Any)] -> [(Fingerprint, Any, Any)]
370+ -- If either list is empty, the intersection must be finished.
373+ -- Merge the two maps considering one element at a time.
374+ mergeMaps (a@(af, _, _) : as) (b@(bf, _, _) : bs) =
375+ case compare af bf of
376+ -- Fingerprints are equal, union the elements using our function
377+ -- If the incoming maps were de-duped, there shouldn't be any other equivalent
379+ EQ -> combine a b : mergeMaps as bs
380+ -- First fingerprint must not be in the second map or we would have seen it by now
381+ -- Skip it an move on
382+ LT -> mergeMaps as (b : bs)
383+ -- Second fingerprint must not be in the first map or we would have seen it by now
384+ -- Skip it an move on
385+ GT -> mergeMaps (a:as) bs
386+{-# INLINE intersectionWith #-}
388+-- | The intersection of two 'TypeRepMap's.
389+-- It keeps all values from the first map whose keys are present in the second.
392+intersection :: TypeRepMap f -> TypeRepMap f -> TypeRepMap f
393+intersection = intersectionWith const
394+{-# INLINE intersection #-}
353{- | Check if a value of the given type is present in a 'TypeRepMap'.
397{- | Check if a value of the given type is present in a 'TypeRepMap'.
355>>> member @Char $ one (Identity 'a')
399>>> member @Char $ one (Identity 'a')
@@ -385,9 +429,22 @@ size = sizeofPrimArray . fingerprintAs
386-- | Return the list of 'SomeTypeRep' from the keys.
430-- | Return the list of 'SomeTypeRep' from the keys.
387keys :: TypeRepMap f -> [SomeTypeRep]
431keys :: TypeRepMap f -> [SomeTypeRep]
388−keys TypeRepMap{..} = SomeTypeRep . anyToTypeRep <$> toList trKeys
432+keys = keysWith SomeTypeRep
389{-# INLINE keys #-}
433{-# INLINE keys #-}
435+-- | Return the list of keys by wrapping them with a user-provided function.
436+keysWith :: (forall (a :: ArgKindOf f). TypeRep a -> r) -> TypeRepMap f -> [r]
437+keysWith f TypeRepMap{..} = f . anyToTypeRep <$> toList trKeys
438+{-# INLINE keysWith #-}
440+-- | Return the list of key-value pairs by wrapping them with a user-provided function.
441+toListWith :: forall f r. (forall (a :: ArgKindOf f). Typeable a => f a -> r) -> TypeRepMap f -> [r]
442+toListWith f = map toF . toTriples
444+ withTypeRep :: TypeRep a -> f a -> r
445+ withTypeRep tr an = withTypeable tr $ f an
446+ toF (_, an, k) = withTypeRep (unsafeCoerce k) (fromAny an)
391-- | Binary searched based on this article
448-- | Binary searched based on this article
392-- http://bannalia.blogspot.com/2015/06/cache-friendly-binary-search.html
449-- http://bannalia.blogspot.com/2015/06/cache-friendly-binary-search.html
393-- with modification for our two-vector search case.
450-- with modification for our two-vector search case.
@@ -464,9 +521,6 @@ data WrapTypeable f where
464instance Show (WrapTypeable f) where
521instance Show (WrapTypeable f) where
465 show (WrapTypeable (_ :: f a)) = show $ calcFp @a
522 show (WrapTypeable (_ :: f a)) = show $ calcFp @a
467−wrapTypeable :: TypeRep a -> f a -> WrapTypeable f
468−wrapTypeable tr = withTypeable tr WrapTypeable
472prop> fromList . toList == 'id'
526prop> fromList . toList == 'id'
@@ -494,10 +548,7 @@ instance IsList (TypeRepMap f) where
494 k (WrapTypeable (_ :: f a)) = unsafeCoerce $ typeRep @a
548 k (WrapTypeable (_ :: f a)) = unsafeCoerce $ typeRep @a
496 toList :: TypeRepMap f -> [WrapTypeable f]
550 toList :: TypeRepMap f -> [WrapTypeable f]
497− toList = map toWrapTypeable . toTriples
551+ toList = toListWith WrapTypeable
499− toWrapTypeable :: (Fingerprint, Any, Any) -> WrapTypeable f
500− toWrapTypeable (_, an, k) = wrapTypeable (unsafeCoerce k) (fromAny an)
502calcFp :: forall a . Typeable a => Fingerprint
553calcFp :: forall a . Typeable a => Fingerprint
503calcFp = typeRepFingerprint $ typeRep @a
554calcFp = typeRepFingerprint $ typeRep @a