@@ -350,6 +350,48 @@ union :: TypeRepMap f -> TypeRepMap f -> TypeRepMap f
350350union = unionWith const
351351{-# INLINE union #-}
352352
353+-- | The 'intersection' of two 'TypeRepMap's using a combining function
354+--
355+-- @O(n + m)@
356+intersectionWith :: forall f. (forall x. Typeable x => f x -> f x -> f x) -> TypeRepMap f -> TypeRepMap f -> TypeRepMap f
357+intersectionWith f ma mb =
358+ fromSortedTriples $ mergeMaps (toSortedTriples ma) (toSortedTriples mb)
359+ where
360+ f' :: forall x. TypeRep x -> f x -> f x -> f x
361+ f' tr = withTypeable tr f
362+
363+ combine :: (Fingerprint, Any, Any) -> (Fingerprint, Any, Any) -> (Fingerprint, Any, Any)
364+ combine (fp, av, ak) (_, bv, _) = (fp, toAny $ f' (fromAny ak) (fromAny av) (fromAny bv), ak)
365+
366+ -- Merges two typrepmaps into a sorted, dedup'd list of triples.
367+ mergeMaps :: [(Fingerprint, Any, Any)] -> [(Fingerprint, Any, Any)] -> [(Fingerprint, Any, Any)]
368+ -- If either list is empty, the intersection must be finished.
369+ mergeMaps _ [] = []
370+ mergeMaps [] _ = []
371+ -- Merge the two maps considering one element at a time.
372+ mergeMaps (a@(af, _, _) : as) (b@(bf, _, _) : bs) =
373+ case compare af bf of
374+ -- Fingerprints are equal, union the elements using our function
375+ -- If the incoming maps were de-duped, there shouldn't be any other equivalent
376+ -- fingerprints
377+ EQ -> combine a b : mergeMaps as bs
378+ -- First fingerprint must not be in the second map or we would have seen it by now
379+ -- Skip it an move on
380+ LT -> mergeMaps as (b : bs)
381+ -- Second fingerprint must not be in the first map or we would have seen it by now
382+ -- Skip it an move on
383+ GT -> mergeMaps (a:as) bs
384+{-# INLINE intersectionWith #-}
385+
386+-- | The intersection of two 'TypeRepMap's.
387+-- It keeps all values from the first map whose keys are present in the second.
388+--
389+-- @O(n + m)@
390+intersection :: TypeRepMap f -> TypeRepMap f -> TypeRepMap f
391+intersection = intersectionWith const
392+{-# INLINE intersection #-}
393+
394+
353395{- | Check if a value of the given type is present in a 'TypeRepMap'.
354396
355397>>> member @Char $ one (Identity 'a')