on develop help sign in
Generalize merge
commit8d8ceecd548f3d4f6e0b8db00a57659511d241a5 authorDavid Feuer <David.Feuer@gmail.com> dateMon 8 Jul 2019, 00:02 (7 years ago) parent7ef47af
7 files changed+141−72
ChangeLog.md+4 reflex.cabal+1 src/Reflex/Class.hs+31−3 src/Reflex/Profiled.hs+9−5 src/Reflex/Pure.hs+16−10 src/Reflex/Spider/Internal.hs+78−53 test/GC.hs+2−1
ChangeLog.md+4
@@ -3,6 +3,10 @@
33## Unreleased
44
55* Fix `holdDyn` so that it is lazy in its event argument
6+* Generalize `merge` to `mergeG`, `mergeIncremental` to
7+ `mergeIncrementalG`, and `mergeIncrementalWithMove`
8+ to `mergeIncrementalWithMoveG`. These produce `DMap`s
9+ whose values needn't be `Identity`.
610
711## 0.6.1.0
812
reflex.cabal+1
@@ -48,6 +48,7 @@ library
4848 data-default >= 0.5 && < 0.8,
4949 dependent-map >= 0.2.4 && < 0.3,
5050 exception-transformers == 0.4.*,
51+ profunctors,
5152 lens >= 4.7 && < 5,
5253 monad-control >= 1.0.1 && < 1.1,
5354 monoidal-containers == 0.4.*,
src/Reflex/Class.hs+31−3
@@ -17,6 +17,7 @@
1717{-# LANGUAGE TypeFamilies #-}
1818{-# LANGUAGE TypeOperators #-}
1919{-# LANGUAGE UndecidableInstances #-}
20+{-# LANGUAGE Trustworthy #-}
2021#ifdef USE_REFLEX_OPTIMIZER
2122{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
2223#endif
@@ -46,6 +47,9 @@ module Reflex.Class
4647 , pushAlways
4748 -- ** Combining 'Event's
4849 , leftmost
50+ , merge
51+ , mergeIncremental
52+ , mergeIncrementalWithMove
4953 , mergeMap
5054 , mergeIntMap
5155 , mergeMapIncremental
@@ -256,7 +260,9 @@ class ( MonadHold t (PushM t)
256260 -- | Merge a collection of events; the resulting 'Event' will only occur if at
257261 -- least one input event is occurring, and will contain all of the input keys
258262 -- that are occurring simultaneously
259− merge :: GCompare k => DMap k (Event t) -> Event t (DMap k Identity) --TODO: Generalize to get rid of DMap use --TODO: Provide a type-level guarantee that the result is not empty
263+ mergeG :: GCompare k => (forall a. q a -> Event t (v a))
264+ -> DMap k q -> Event t (DMap k v)
265+ --TODO: Generalize to get rid of DMap use --TODO: Provide a type-level guarantee that the result is not empty
260266 -- | Efficiently fan-out an event to many destinations. You should save the
261267 -- result in a @let@-binding, and then repeatedly 'select' on the result to
262268 -- create child events
@@ -278,9 +284,14 @@ class ( MonadHold t (PushM t)
278284 -- that value.
279285 unsafeBuildIncremental :: Patch p => PullM t (PatchTarget p) -> Event t p -> Incremental t p
280286 -- | Create a merge whose parents can change over time
281− mergeIncremental :: GCompare k => Incremental t (PatchDMap k (Event t)) -> Event t (DMap k Identity)
287+ mergeIncrementalG :: GCompare k
288+ => (forall a. q a -> Event t (v a))
289+ -> Incremental t (PatchDMap k q)
290+ -> Event t (DMap k v)
282291 -- | Experimental: Create a merge whose parents can change over time; changing the key of an Event is more efficient than with mergeIncremental
283− mergeIncrementalWithMove :: GCompare k => Incremental t (PatchDMapWithMove k (Event t)) -> Event t (DMap k Identity)
292+ mergeIncrementalWithMoveG :: GCompare k
293+ => (forall a. q a -> Event t (v a))
294+ -> Incremental t (PatchDMapWithMove k q) -> Event t (DMap k v)
284295 -- | Extract the 'Behavior' component of an 'Incremental'
285296 currentIncremental :: Patch p => Incremental t p -> Behavior t (PatchTarget p)
286297 -- | Extract the 'Event' component of an 'Incremental'
@@ -1558,6 +1569,23 @@ fmapCheap f = pushCheap $ return . Just . f
15581569tagCheap :: Reflex t => Behavior t b -> Event t a -> Event t b
15591570tagCheap b = pushAlwaysCheap $ \_ -> sample b
15601571
1572+-- | Merge a collection of events; the resulting 'Event' will only occur if at
1573+-- least one input event is occurring, and will contain all of the input keys
1574+-- that are occurring simultaneously
1575+merge :: (Reflex t, GCompare k) => DMap k (Event t) -> Event t (DMap k Identity)
1576+merge = mergeG coerceEvent
1577+{-# INLINE merge #-}
1578+
1579+-- | Create a merge whose parents can change over time
1580+mergeIncremental :: (Reflex t, GCompare k)
1581+ => Incremental t (PatchDMap k (Event t)) -> Event t (DMap k Identity)
1582+mergeIncremental = mergeIncrementalG coerceEvent
1583+
1584+-- | Experimental: Create a merge whose parents can change over time; changing the key of an Event is more efficient than with mergeIncremental
1585+mergeIncrementalWithMove :: (Reflex t, GCompare k)
1586+ => Incremental t (PatchDMapWithMove k (Event t)) -> Event t (DMap k Identity)
1587+mergeIncrementalWithMove = mergeIncrementalWithMoveG coerceEvent
1588+
15611589-- | A "cheap" version of 'mergeWithCheap'. See the performance note on 'pushCheap'.
15621590{-# INLINE mergeWithCheap #-}
15631591mergeWithCheap :: Reflex t => (a -> a -> a) -> [Event t a] -> Event t a
src/Reflex/Profiled.hs+9−5
@@ -8,6 +8,8 @@
88{-# LANGUAGE StandaloneDeriving #-}
99{-# LANGUAGE TypeFamilies #-}
1010{-# LANGUAGE UndecidableInstances #-}
11+{-# LANGUAGE PolyKinds #-}
12+{-# LANGUAGE RankNTypes #-}
1113-- |
1214-- Module:
1315-- Reflex.Profiled
@@ -16,7 +18,6 @@
1618-- profiling/cost-center information.
1719module Reflex.Profiled where
1820
19−import Control.Lens hiding (children)
2021import Control.Monad
2122import Control.Monad.Exception
2223import Control.Monad.Fix
@@ -33,6 +34,7 @@ import Data.Map (Map)
3334import qualified Data.Map.Strict as Map
3435import Data.Monoid ((<>))
3536import Data.Ord
37+import Data.Profunctor.Unsafe ((#.))
3638import qualified Data.Semigroup as S
3739import Data.Type.Coercion
3840import Foreign.Ptr
@@ -133,8 +135,10 @@ instance Reflex t => Reflex (ProfiledTimeline t) where
133135 push f (Event_Profiled e) = coerce $ push (coerce f) $ profileEvent e -- Profile before rather than after; this way fanout won't count against us
134136 pushCheap f (Event_Profiled e) = coerce $ pushCheap (coerce f) $ profileEvent e
135137 pull = Behavior_Profiled . pull . coerce
136− merge :: forall k. GCompare k => DMap k (Event (ProfiledTimeline t)) -> Event (ProfiledTimeline t) (DMap k Identity)
137− merge = Event_Profiled . merge . (unsafeCoerce :: DMap k (Event (ProfiledTimeline t)) -> DMap k (Event t))
138+ mergeG :: forall (k :: z -> *) q v. GCompare k
139+ => (forall a. q a -> Event (ProfiledTimeline t) (v a))
140+ -> DMap k q -> Event (ProfiledTimeline t) (DMap k v)
141+ mergeG nt = Event_Profiled #. mergeG (coerce nt)
138142 fan (Event_Profiled e) = EventSelector $ coerce $ select (fan $ profileEvent e)
139143 switch (Behavior_Profiled b) = coerce $ profileEvent $ switch (coerceBehavior b)
140144 coincidence (Event_Profiled e) = coerce $ profileEvent $ coincidence (coerceEvent e)
@@ -142,8 +146,8 @@ instance Reflex t => Reflex (ProfiledTimeline t) where
142146 updated (Dynamic_Profiled d) = coerce $ profileEvent $ updated d
143147 unsafeBuildDynamic (ProfiledM a0) (Event_Profiled a') = coerce $ unsafeBuildDynamic a0 a'
144148 unsafeBuildIncremental (ProfiledM a0) (Event_Profiled a') = coerce $ unsafeBuildIncremental a0 a'
145− mergeIncremental = Event_Profiled . mergeIncremental . (unsafeCoerce :: Incremental (ProfiledTimeline t) (PatchDMap k (Event (ProfiledTimeline t))) -> Incremental t (PatchDMap k (Event t)))
146− mergeIncrementalWithMove = Event_Profiled . mergeIncrementalWithMove . (unsafeCoerce :: Incremental (ProfiledTimeline t) (PatchDMapWithMove k (Event (ProfiledTimeline t))) -> Incremental t (PatchDMapWithMove k (Event t)))
149+ mergeIncrementalG nt = (Event_Profiled . coerce) #. mergeIncrementalG nt
150+ mergeIncrementalWithMoveG nt = (Event_Profiled . coerce) #. mergeIncrementalWithMoveG nt
147151 currentIncremental (Incremental_Profiled i) = coerce $ currentIncremental i
148152 updatedIncremental (Incremental_Profiled i) = coerce $ profileEvent $ updatedIncremental i
149153 incrementalToDynamic (Incremental_Profiled i) = coerce $ incrementalToDynamic i
src/Reflex/Pure.hs+16−10
@@ -5,6 +5,8 @@
55{-# LANGUAGE MultiParamTypeClasses #-}
66{-# LANGUAGE ScopedTypeVariables #-}
77{-# LANGUAGE TypeFamilies #-}
8+{-# LANGUAGE RankNTypes #-}
9+{-# LANGUAGE PolyKinds #-}
810#ifdef USE_REFLEX_OPTIMIZER
911{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
1012#endif
@@ -43,10 +45,11 @@ import Data.MemoTrie
4345import Data.Monoid
4446import Data.Type.Coercion
4547import Reflex.Class
48+import Data.Kind (Type)
4649
4750-- | A completely pure-functional 'Reflex' timeline, identifying moments in time
4851-- with the type @/t/@.
49−data Pure t
52+data Pure (t :: Type)
5053
5154-- | The 'Enum' instance of @/t/@ must be dense: for all @/x :: t/@, there must not exist
5255-- any @/y :: t/@ such that @/'pred' x < y < x/@. The 'HasTrie' instance will be used
@@ -79,11 +82,12 @@ instance (Enum t, HasTrie t, Ord t) => Reflex (Pure t) where
7982 -- [UNUSED_CONSTRAINT]: The following type signature for merge will produce a
8083 -- warning because the GCompare instance is not used; however, removing the
8184 -- GCompare instance produces a different warning, due to that constraint
82− -- being present in the original class definition
85+ -- being present in the original class definition.
8386
84− --merge :: GCompare k => DMap k (Event (Pure t)) -> Event (Pure t) (DMap k Identity)
85− merge events = Event $ memo $ \t ->
86− let currentOccurrences = DMap.mapMaybeWithKey (\_ (Event a) -> Identity <$> a t) events
87+ --mergeG :: GCompare k => (forall a. q a -> Event (Pure t) (v a))
88+ -- -> DMap k q -> Event (Pure t) (DMap k v)
89+ mergeG nt events = Event $ memo $ \t ->
90+ let currentOccurrences = DMap.mapMaybeWithKey (\_ q -> case nt q of Event a -> a t) events
8791 in if DMap.null currentOccurrences
8892 then Nothing
8993 else Just currentOccurrences
@@ -112,8 +116,8 @@ instance (Enum t, HasTrie t, Ord t) => Reflex (Pure t) where
112116 --a) -> Incremental (Pure t) p a
113117 unsafeBuildIncremental readV0 p = Incremental $ \t -> (readV0 t, unEvent p t)
114118
115− mergeIncremental = mergeIncrementalImpl
116− mergeIncrementalWithMove = mergeIncrementalImpl
119+ mergeIncrementalG = mergeIncrementalImpl
120+ mergeIncrementalWithMoveG = mergeIncrementalImpl
117121
118122 currentIncremental i = Behavior $ \t -> fst $ unIncremental i t
119123
@@ -133,9 +137,11 @@ instance (Enum t, HasTrie t, Ord t) => Reflex (Pure t) where
133137
134138 mergeIntIncremental = mergeIntIncrementalImpl
135139
136−mergeIncrementalImpl :: (PatchTarget p ~ DMap k (Event (Pure t)), GCompare k) => Incremental (Pure t) p -> Event (Pure t) (DMap k Identity)
137−mergeIncrementalImpl i = Event $ \t ->
138− let results = DMap.mapMaybeWithKey (\_ (Event e) -> Identity <$> e t) $ fst $ unIncremental i t
140+mergeIncrementalImpl :: (PatchTarget p ~ DMap k q, GCompare k)
141+ => (forall a. q a -> Event (Pure t) (v a))
142+ -> Incremental (Pure t) p -> Event (Pure t) (DMap k v)
143+mergeIncrementalImpl nt i = Event $ \t ->
144+ let results = DMap.mapMaybeWithKey (\_ q -> case nt q of Event e -> e t) $ fst $ unIncremental i t
139145 in if DMap.null results
140146 then Nothing
141147 else Just results
src/Reflex/Spider/Internal.hs+78−53
@@ -17,9 +17,12 @@
1717{-# LANGUAGE TypeFamilies #-}
1818{-# LANGUAGE TypeOperators #-}
1919{-# LANGUAGE UndecidableInstances #-}
20+{-# LANGUAGE PolyKinds #-}
21+{-# LANGUAGE InstanceSigs #-}
2022#ifdef USE_REFLEX_OPTIMIZER
2123{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
2224#endif
25+{-# OPTIONS_GHC -Wunused-binds #-}
2326-- | This module is the implementation of the 'Spider' 'Reflex' engine. It uses
2427-- a graph traversal algorithm to propagate 'Event's and 'Behavior's.
2528module Reflex.Spider.Internal (module Reflex.Spider.Internal) where
@@ -49,6 +52,7 @@ import Data.GADT.Compare
4952import Data.IntMap.Strict (IntMap)
5053import qualified Data.IntMap.Strict as IntMap
5154import Data.IORef
55+import Data.Kind (Type)
5256import Data.Maybe hiding (mapMaybe)
5357import Data.Monoid ((<>))
5458import Data.Proxy
@@ -77,6 +81,7 @@ import Data.Reflection
7781import Data.Some (Some)
7882import qualified Data.Some as Some
7983import Data.Type.Coercion
84+import Data.Profunctor.Unsafe ((#.), (.#))
8085import Data.WeakBag (WeakBag, WeakBagTicket, _weakBag_children)
8186import qualified Data.WeakBag as WeakBag
8287import qualified Reflex.Class
@@ -1136,13 +1141,14 @@ instance HasSpiderTimeline x => Align (Event x) where
11361141#if MIN_VERSION_these(0, 8, 0)
11371142instance HasSpiderTimeline x => Semialign (Event x) where
11381143#endif
1139− align ea eb = mapMaybe dmapToThese $ merge $ dynamicConst $ DMap.fromDistinctAscList [LeftTag :=> ea, RightTag :=> eb]
1144+ align ea eb = mapMaybe dmapToThese $ mergeG coerce $ dynamicConst $
1145+ DMap.fromDistinctAscList [LeftTag :=> ea, RightTag :=> eb]
11401146
11411147data DynType x p = UnsafeDyn !(BehaviorM x (PatchTarget p), Event x p)
11421148 | BuildDyn !(EventM x (PatchTarget p), Event x p)
11431149 | HoldDyn !(Hold x p)
11441150
1145−newtype Dyn x p = Dyn { unDyn :: IORef (DynType x p) }
1151+newtype Dyn (x :: Type) p = Dyn { unDyn :: IORef (DynType x p) }
11461152
11471153newMapDyn :: HasSpiderTimeline x => (a -> b) -> Dynamic x (Identity a) -> Dynamic x (Identity b)
11481154newMapDyn f d = dynamicDynIdentity $ unsafeBuildDynamic (fmap f $ readBehaviorTracked $ dynamicCurrent d) (Identity . f . runIdentity <$> dynamicUpdated d)
@@ -1688,26 +1694,34 @@ cleanupCoincidenceSubscribed subscribed = do
16881694subscribeCoincidenceSubscribed :: CoincidenceSubscribed x a -> Subscriber x a -> IO WeakBagTicket
16891695subscribeCoincidenceSubscribed subscribed sub = WeakBag.insert sub (coincidenceSubscribedSubscribers subscribed) (coincidenceSubscribedWeakSelf subscribed) cleanupCoincidenceSubscribed
16901696
1691−{-# INLINE merge #-}
1692−merge :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMap k (Event x)) -> Event x (DMap k Identity)
1693−merge d = cacheEvent (mergeCheap d)
1697+{-# INLINE mergeG #-}
1698+mergeG :: forall k q x v. (HasSpiderTimeline x, GCompare k)
1699+ => (forall a. q a -> Event x (v a))
1700+ -> Dynamic x (PatchDMap k q) -> Event x (DMap k v)
1701+mergeG nt d = cacheEvent (mergeCheap nt d)
16941702
16951703{-# INLINE mergeWithMove #-}
1696−mergeWithMove :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMapWithMove k (Event x)) -> Event x (DMap k Identity)
1697−mergeWithMove d = cacheEvent (mergeCheapWithMove d)
1704+mergeWithMove :: forall k v q x. (HasSpiderTimeline x, GCompare k)
1705+ => (forall a. q a -> Event x (v a))
1706+ -> Dynamic x (PatchDMapWithMove k q) -> Event x (DMap k v)
1707+mergeWithMove nt d = cacheEvent (mergeCheapWithMove nt d)
16981708
16991709{-# INLINE [1] mergeCheap #-}
1700−mergeCheap :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMap k (Event x)) -> Event x (DMap k Identity)
1701−mergeCheap = mergeCheap' getInitialSubscribers updateMe destroy
1710+mergeCheap
1711+ :: forall k x q v. (HasSpiderTimeline x, GCompare k)
1712+ => (forall a. q a -> Event x (v a))
1713+ -> Dynamic x (PatchDMap k q)
1714+ -> Event x (DMap k v)
1715+mergeCheap nt = mergeGCheap' getInitialSubscribers updateMe destroy
17021716 where
1703− updateMe :: MergeUpdateFunc k x (PatchDMap k (Event x)) (MergeSubscribedParent x)
1717+ updateMe :: MergeUpdateFunc k v x (PatchDMap k q) (MergeSubscribedParent x)
17041718 updateMe subscriber heightBagRef oldParents (PatchDMap p) = do
17051719 let f (subscriptionsToKill, ps) (k :=> ComposeMaybe me) = do
17061720 (mOldSubd, newPs) <- case me of
17071721 Nothing -> return $ DMap.updateLookupWithKey (\_ _ -> Nothing) k ps
17081722 Just e -> do
17091723 let s = subscriber $ return k
1710− subscription@(EventSubscription _ subd) <- subscribe e s
1724+ subscription@(EventSubscription _ subd) <- subscribe (nt e) s
17111725 newParentHeight <- liftIO $ getEventSubscribedHeight subd
17121726 let newParent = MergeSubscribedParent subscription
17131727 liftIO $ modifyIORef' heightBagRef $ heightBagAdd newParentHeight
@@ -1717,28 +1731,33 @@ mergeCheap = mergeCheap' getInitialSubscribers updateMe destroy
17171731 liftIO $ modifyIORef heightBagRef $ heightBagRemove oldHeight
17181732 return (maybeToList (unMergeSubscribedParent <$> mOldSubd) ++ subscriptionsToKill, newPs)
17191733 foldM f ([], oldParents) $ DMap.toList p
1720− getInitialSubscribers :: MergeInitFunc k x (MergeSubscribedParent x)
1734+
1735+ getInitialSubscribers :: MergeInitFunc k v q x (MergeSubscribedParent x)
17211736 getInitialSubscribers initialParents subscriber = do
17221737 subscribers <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
17231738 let s = subscriber $ return k
1724− (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead e s
1739+ (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead (nt e) s
17251740 height <- liftIO $ getEventSubscribedHeight parentSubd
1726− return (fmap (\x -> k :=> Identity x) parentOcc, height, k :=> MergeSubscribedParent subscription)
1741+ return (fmap (\x -> k :=> x) parentOcc, height, k :=> MergeSubscribedParent subscription)
17271742 return ( DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
17281743 , fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
17291744 , DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
17301745 )
1746+
17311747 destroy :: MergeDestroyFunc k (MergeSubscribedParent x)
17321748 destroy s = forM_ (DMap.toList s) $ \(_ :=> MergeSubscribedParent sub) -> unsubscribe sub
17331749
17341750{-# INLINE [1] mergeCheapWithMove #-}
1735−mergeCheapWithMove :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMapWithMove k (Event x)) -> Event x (DMap k Identity)
1736−mergeCheapWithMove = mergeCheap' getInitialSubscribers updateMe destroy
1751+mergeCheapWithMove :: forall k x v q. (HasSpiderTimeline x, GCompare k)
1752+ => (forall a. q a -> Event x (v a))
1753+ -> Dynamic x (PatchDMapWithMove k q)
1754+ -> Event x (DMap k v)
1755+mergeCheapWithMove nt = mergeGCheap' getInitialSubscribers updateMe destroy
17371756 where
1738− updateMe :: MergeUpdateFunc k x (PatchDMapWithMove k (Event x)) (MergeSubscribedParentWithMove x k)
1757+ updateMe :: MergeUpdateFunc k v x (PatchDMapWithMove k q) (MergeSubscribedParentWithMove x k)
17391758 updateMe subscriber heightBagRef oldParents p = do
17401759 -- Prepare new parents for insertion
1741− let subscribeParent :: forall a. k a -> Event x a -> EventM x (MergeSubscribedParentWithMove x k a)
1760+ let subscribeParent :: forall a. k a -> Event x (v a) -> EventM x (MergeSubscribedParentWithMove x k a)
17421761 subscribeParent k e = do
17431762 keyRef <- liftIO $ newIORef k
17441763 let s = subscriber $ liftIO $ readIORef keyRef
@@ -1747,9 +1766,9 @@ mergeCheapWithMove = mergeCheap' getInitialSubscribers updateMe destroy
17471766 newParentHeight <- getEventSubscribedHeight subd
17481767 modifyIORef' heightBagRef $ heightBagAdd newParentHeight
17491768 return $ MergeSubscribedParentWithMove subscription keyRef
1750− p' <- PatchDMapWithMove.traversePatchDMapWithMoveWithKey subscribeParent p
1769+ p' <- PatchDMapWithMove.traversePatchDMapWithMoveWithKey (\k q -> subscribeParent k (nt q)) p
17511770 -- Collect old parents for deletion and update the keys of moved parents
1752− let moveOrDelete :: forall a. k a -> PatchDMapWithMove.NodeInfo k (Event x) a -> MergeSubscribedParentWithMove x k a -> Constant (EventM x (Maybe (EventSubscription x))) a
1771+ let moveOrDelete :: forall a. k a -> PatchDMapWithMove.NodeInfo k q a -> MergeSubscribedParentWithMove x k a -> Constant (EventM x (Maybe (EventSubscription x))) a
17531772 moveOrDelete _ ni parent = Constant $ case getComposeMaybe $ PatchDMapWithMove._nodeInfo_to ni of
17541773 Nothing -> do
17551774 oldHeight <- liftIO $ getEventSubscribedHeight $ _eventSubscription_subscribed $ _mergeSubscribedParentWithMove_subscription parent
@@ -1760,46 +1779,47 @@ mergeCheapWithMove = mergeCheap' getInitialSubscribers updateMe destroy
17601779 return Nothing
17611780 toDelete <- fmap catMaybes $ mapM (\(_ :=> v) -> getConstant v) $ DMap.toList $ DMap.intersectionWithKey moveOrDelete (unPatchDMapWithMove p) oldParents
17621781 return (toDelete, applyAlways p' oldParents)
1763− getInitialSubscribers :: MergeInitFunc k x (MergeSubscribedParentWithMove x k)
1782+ getInitialSubscribers :: MergeInitFunc k v q x (MergeSubscribedParentWithMove x k)
17641783 getInitialSubscribers initialParents subscriber = do
17651784 subscribers <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
17661785 keyRef <- liftIO $ newIORef k
17671786 let s = subscriber $ liftIO $ readIORef keyRef
1768− (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead e s
1787+ (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead (nt e) s
17691788 height <- liftIO $ getEventSubscribedHeight parentSubd
1770− return (fmap (\x -> k :=> Identity x) parentOcc, height, k :=> MergeSubscribedParentWithMove subscription keyRef)
1789+ return (fmap (\x -> k :=> x) parentOcc, height, k :=> MergeSubscribedParentWithMove subscription keyRef)
17711790 return ( DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
17721791 , fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
17731792 , DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
17741793 )
1794+
17751795 destroy :: MergeDestroyFunc k (MergeSubscribedParentWithMove x k)
17761796 destroy s = forM_ (DMap.toList s) $ \(_ :=> MergeSubscribedParentWithMove sub _) -> unsubscribe sub
17771797
1778−type MergeUpdateFunc k x p s
1779− = (forall a. EventM x (k a) -> Subscriber x a)
1798+type MergeUpdateFunc k v x p s
1799+ = (forall a. EventM x (k a) -> Subscriber x (v a))
17801800 -> IORef HeightBag
17811801 -> DMap k s
17821802 -> p
17831803 -> EventM x ([EventSubscription x], DMap k s)
17841804
1785−type MergeInitFunc k x s
1786− = DMap k (Event x)
1787− -> (forall a. EventM x (k a) -> Subscriber x a)
1788− -> EventM x (DMap k Identity, [Height], DMap k s)
1805+type MergeInitFunc k v q x s
1806+ = DMap k q
1807+ -> (forall a. EventM x (k a) -> Subscriber x (v a))
1808+ -> EventM x (DMap k v, [Height], DMap k s)
17891809
17901810type MergeDestroyFunc k s
17911811 = DMap k s
17921812 -> IO ()
17931813
1794−data Merge x k s = Merge
1814+data Merge x k v s = Merge
17951815 { _merge_parentsRef :: {-# UNPACK #-} !(IORef (DMap k s))
17961816 , _merge_heightBagRef :: {-# UNPACK #-} !(IORef HeightBag)
17971817 , _merge_heightRef :: {-# UNPACK #-} !(IORef Height)
1798− , _merge_sub :: {-# UNPACK #-} !(Subscriber x (DMap k Identity))
1799− , _merge_accumRef :: {-# UNPACK #-} !(IORef (DMap k Identity))
1818+ , _merge_sub :: {-# UNPACK #-} !(Subscriber x (DMap k v))
1819+ , _merge_accumRef :: {-# UNPACK #-} !(IORef (DMap k v))
18001820 }
18011821
1802−invalidateMergeHeight :: Merge x k s -> IO ()
1822+invalidateMergeHeight :: Merge x k v s -> IO ()
18031823invalidateMergeHeight m = invalidateMergeHeight' (_merge_heightRef m) (_merge_sub m)
18041824
18051825invalidateMergeHeight' :: IORef Height -> Subscriber x a -> IO ()
@@ -1809,8 +1829,7 @@ invalidateMergeHeight' heightRef sub = do
18091829 writeIORef heightRef $! invalidHeight
18101830 subscriberInvalidateHeight sub oldHeight
18111831
1812−
1813−revalidateMergeHeight :: Merge x k s -> IO ()
1832+revalidateMergeHeight :: Merge x k v s -> IO ()
18141833revalidateMergeHeight m = do
18151834 currentHeight <- readIORef $ _merge_heightRef m
18161835 when (currentHeight == invalidHeight) $ do -- revalidateMergeHeight may be called multiple times; perhaps the's a way to finesse it to avoid this check
@@ -1826,19 +1845,19 @@ revalidateMergeHeight m = do
18261845 subscriberRecalculateHeight (_merge_sub m) height
18271846 GT -> error $ "revalidateMergeHeight: more heights (" <> show (heightBagSize heights) <> ") than parents (" <> show (DMap.size parents) <> ") for Merge"
18281847
1829−scheduleMergeSelf :: HasSpiderTimeline x => Merge x k s -> Height -> EventM x ()
1848+scheduleMergeSelf :: HasSpiderTimeline x => Merge x k v s -> Height -> EventM x ()
18301849scheduleMergeSelf m height = scheduleMerge' height (_merge_heightRef m) $ do
18311850 vals <- liftIO $ readIORef $ _merge_accumRef m
18321851 liftIO $ writeIORef (_merge_accumRef m) $! DMap.empty -- Once we're done with this, we can clear it immediately, because if there's a cacheEvent in front of us, it'll handle subsequent subscribers, and if not, we won't get subsequent subscribers
18331852 --TODO: Assert that m is not empty
18341853 subscriberPropagate (_merge_sub m) vals
18351854
1836−mergeSubscriber :: forall x k s a. (HasSpiderTimeline x, GCompare k) => Merge x k s -> EventM x (k a) -> Subscriber x a
1855+mergeSubscriber :: forall x k v s a. (HasSpiderTimeline x, GCompare k) => Merge x k v s -> EventM x (k a) -> Subscriber x (v a)
18371856mergeSubscriber m getKey = Subscriber
18381857 { subscriberPropagate = \a -> do
18391858 oldM <- liftIO $ readIORef $ _merge_accumRef m
18401859 k <- getKey
1841− let newM = DMap.insertWith (error $ "Same key fired multiple times for Merge") k (Identity a) oldM
1860+ let newM = DMap.insertWith (error $ "Same key fired multiple times for Merge") k a oldM
18421861 tracePropagate (Proxy :: Proxy x) $ " DMap.size oldM = " <> show (DMap.size oldM) <> "; DMap.size newM = " <> show (DMap.size newM)
18431862 liftIO $ writeIORef (_merge_accumRef m) $! newM
18441863 when (DMap.null oldM) $ do -- Only schedule the firing once
@@ -1869,7 +1888,7 @@ mergeSubscriber m getKey = Subscriber
18691888 }
18701889
18711890--TODO: Be able to run as much of this as possible promptly
1872−updateMerge :: (HasSpiderTimeline x, GCompare k) => Merge x k s -> MergeUpdateFunc k x p s -> p -> SomeMergeUpdate x
1891+updateMerge :: (HasSpiderTimeline x, GCompare k) => Merge x k v s -> MergeUpdateFunc k v x p s -> p -> SomeMergeUpdate x
18731892updateMerge m updateFunc p = SomeMergeUpdate updateMe (invalidateMergeHeight m) (revalidateMergeHeight m)
18741893 where updateMe = do
18751894 oldParents <- liftIO $ readIORef $ _merge_parentsRef m
@@ -1877,9 +1896,10 @@ updateMerge m updateFunc p = SomeMergeUpdate updateMe (invalidateMergeHeight m)
18771896 liftIO $ writeIORef (_merge_parentsRef m) $! newParents
18781897 return subscriptionsToKill
18791898
1880−{-# INLINE mergeCheap' #-}
1881−mergeCheap' :: forall k x p s. (HasSpiderTimeline x, GCompare k, PatchTarget p ~ DMap k (Event x)) => MergeInitFunc k x s -> MergeUpdateFunc k x p s -> MergeDestroyFunc k s -> Dynamic x p -> Event x (DMap k Identity)
1882−mergeCheap' getInitialSubscribers updateFunc destroy d = Event $ \sub -> do
1899+{-# INLINE mergeGCheap' #-}
1900+mergeGCheap' :: forall k v x p s q. (HasSpiderTimeline x, GCompare k, PatchTarget p ~ DMap k q)
1901+ => MergeInitFunc k v q x s -> MergeUpdateFunc k v x p s -> MergeDestroyFunc k s -> Dynamic x p -> Event x (DMap k v)
1902+mergeGCheap' getInitialSubscribers updateFunc destroy d = Event $ \sub -> do
18831903 initialParents <- readBehaviorUntracked $ dynamicCurrent d
18841904 accumRef <- liftIO $ newIORef $ error "merge: accumRef not yet initialized"
18851905 heightRef <- liftIO $ newIORef $ error "merge: heightRef not yet initialized"
@@ -2462,7 +2482,7 @@ unsafeNewSpiderTimelineEnv = do
24622482newSpiderTimeline :: IO (Some SpiderTimelineEnv)
24632483newSpiderTimeline = withSpiderTimeline (pure . Some.This)
24642484
2465−data LocalSpiderTimeline x s
2485+data LocalSpiderTimeline (x :: Type) s
24662486
24672487instance Reifies s (SpiderTimelineEnv x) =>
24682488 HasSpiderTimeline (LocalSpiderTimeline x s) where
@@ -2480,11 +2500,11 @@ withSpiderTimeline k = do
24802500 env <- unsafeNewSpiderTimelineEnv
24812501 reify env $ \s -> k $ localSpiderTimeline s env
24822502
2483−newtype SpiderPullM x a = SpiderPullM (BehaviorM x a) deriving (Functor, Applicative, Monad, MonadIO, MonadFix)
2503+newtype SpiderPullM (x :: Type) a = SpiderPullM (BehaviorM x a) deriving (Functor, Applicative, Monad, MonadIO, MonadFix)
24842504
24852505type ComputeM = EventM
24862506
2487−newtype SpiderPushM x a = SpiderPushM (ComputeM x a) deriving (Functor, Applicative, Monad, MonadIO, MonadFix)
2507+newtype SpiderPushM (x :: Type) a = SpiderPushM (ComputeM x a) deriving (Functor, Applicative, Monad, MonadIO, MonadFix)
24882508
24892509instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
24902510 {-# SPECIALIZE instance R.Reflex (SpiderTimeline Global) #-}
@@ -2504,8 +2524,13 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
25042524 pushCheap f = SpiderEvent . pushCheap (coerce f) . unSpiderEvent
25052525 {-# INLINABLE pull #-}
25062526 pull = SpiderBehavior . pull . coerce
2507− {-# INLINABLE merge #-}
2508− merge = SpiderEvent . merge . dynamicConst . (coerce :: DMap k (R.Event (SpiderTimeline x)) -> DMap k (Event x))
2527+ {-# INLINABLE mergeG #-}
2528+ mergeG
2529+ :: forall (k :: k2 -> *) q (v :: k2 -> *). GCompare k
2530+ => (forall a. q a -> R.Event (SpiderTimeline x) (v a))
2531+ -> DMap k q
2532+ -> R.Event (SpiderTimeline x) (DMap k v)
2533+ mergeG nt = SpiderEvent . mergeG (unSpiderEvent #. nt) . dynamicConst
25092534 {-# INLINABLE fan #-}
25102535 fan e = R.EventSelector $ SpiderEvent . select (fan (unSpiderEvent e))
25112536 {-# INLINABLE switch #-}
@@ -2520,10 +2545,10 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
25202545 unsafeBuildDynamic readV0 v' = SpiderDynamic $ dynamicDynIdentity $ unsafeBuildDynamic (coerce readV0) $ coerce $ unSpiderEvent v'
25212546 {-# INLINABLE unsafeBuildIncremental #-}
25222547 unsafeBuildIncremental readV0 dv = SpiderIncremental $ dynamicDyn $ unsafeBuildDynamic (coerce readV0) $ unSpiderEvent dv
2523− {-# INLINABLE mergeIncremental #-}
2524− mergeIncremental = SpiderEvent . merge . (unsafeCoerce :: Dynamic x (PatchDMap k (R.Event (SpiderTimeline x))) -> Dynamic x (PatchDMap k (Event x))) . unSpiderIncremental
2525− {-# INLINABLE mergeIncrementalWithMove #-}
2526− mergeIncrementalWithMove = SpiderEvent . mergeWithMove . (unsafeCoerce :: Dynamic x (PatchDMapWithMove k (R.Event (SpiderTimeline x))) -> Dynamic x (PatchDMapWithMove k (Event x))) . unSpiderIncremental
2548+ {-# INLINABLE mergeIncrementalG #-}
2549+ mergeIncrementalG nt = SpiderEvent #. mergeG (coerce #. nt) .# unSpiderIncremental
2550+ {-# INLINABLE mergeIncrementalWithMoveG #-}
2551+ mergeIncrementalWithMoveG nt = SpiderEvent #. mergeWithMove (coerce #. nt) .# unSpiderIncremental
25272552 {-# INLINABLE currentIncremental #-}
25282553 currentIncremental = SpiderBehavior . dynamicCurrent . unSpiderIncremental
25292554 {-# INLINABLE updatedIncremental #-}
@@ -2561,7 +2586,7 @@ instance MonadAtomicRef (EventM x) where
25612586 atomicModifyRef r f = liftIO $ atomicModifyRef r f
25622587
25632588-- | The monad for actions that manipulate a Spider timeline identified by @x@
2564−newtype SpiderHost x a = SpiderHost { unSpiderHost :: IO a } deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
2589+newtype SpiderHost (x :: Type) a = SpiderHost { unSpiderHost :: IO a } deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
25652590
25662591instance Monad (SpiderHost x) where
25672592 {-# INLINABLE (>>=) #-}
@@ -2583,7 +2608,7 @@ runSpiderHost (SpiderHost a) = a
25832608runSpiderHostForTimeline :: SpiderHost x a -> SpiderTimelineEnv x -> IO a
25842609runSpiderHostForTimeline (SpiderHost a) _ = a
25852610
2586−newtype SpiderHostFrame x a = SpiderHostFrame { runSpiderHostFrame :: EventM x a }
2611+newtype SpiderHostFrame (x :: Type) a = SpiderHostFrame { runSpiderHostFrame :: EventM x a }
25872612 deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
25882613
25892614instance Monad (SpiderHostFrame x) where
test/GC.hs+2−1
@@ -27,6 +27,7 @@ import qualified Reflex.Spider.Internal as S
2727
2828import System.Exit
2929import System.Mem
30+import Data.Coerce
3031
3132main :: IO ()
3233main = do
@@ -46,7 +47,7 @@ hostPerf ref = S.runSpiderHost $ do
4647 eventToPerform <- Host.runHostFrame $ do
4748 (reqMap :: S.Event S.Global (DMap (Const2 Int (DMap Tell (S.SpiderHostFrame S.Global))) Identity))
4849 <- S.SpiderHostFrame
49− $ fmap ( S.merge
50+ $ fmap ( S.mergeG coerce
5051 . S.dynamicHold)
5152 $ S.hold DMap.empty
5253 -- Construct a new heap object for the subscriber, invalidating any weak references to the subscriber if they are not retained