on develop help sign in
Merge pull request #215 from Saulzar/build_dynamic

buildDynamic as PushM

commit63442b9cb35494d81325eb8ecd78b60564507ca2 authorRyan Trinkle <ryan.trinkle@gmail.com> dateTue 14 Aug 2018, 12:01 (8 years ago) parent39d9392147ba41
9 files changed+144−36
src/Reflex/Class.hs+23−11 src/Reflex/Dynamic.hs+14−10 src/Reflex/DynamicWriter/Base.hs+7−1 src/Reflex/Query/Base.hs+6−1 src/Reflex/Spider/Internal.hs+19−8 test/Reflex/Test/CrossImpl.hs+3 test/Reflex/Test/Micro.hs+64−3 test/Test/Run.hs+8 test/semantics.hs−2
src/Reflex/Class.hs+23−11
@@ -61,6 +61,7 @@ module Reflex.Class
6161 , eitherToDSum
6262 , dsumToEither
6363 , factorEvent
64+ , filterEventKey
6465 -- ** Collapsing 'Event . Event'
6566 , switchHold
6667 , switchHoldPromptly
@@ -337,7 +338,7 @@ class MonadSample t m => MonadHold t m where
337338 holdIncremental :: Patch p => PatchTarget p -> Event t p -> m (Incremental t p)
338339 default holdIncremental :: (Patch p, m ~ f m', MonadTrans f, MonadHold t m') => PatchTarget p -> Event t p -> m (Incremental t p)
339340 holdIncremental v0 = lift . holdIncremental v0
340− buildDynamic :: PullM t a -> Event t a -> m (Dynamic t a)
341+ buildDynamic :: PushM t a -> Event t a -> m (Dynamic t a)
341342 {-
342343 default buildDynamic :: (m ~ f m', MonadTrans f, MonadHold t m') => PullM t a -> Event t a -> m (Dynamic t a)
343344 buildDynamic getV0 = lift . buildDynamic getV0
@@ -904,6 +905,24 @@ alignEventWithMaybe f ea eb =
904905 $ merge
905906 $ DMap.fromList [LeftTag :=> ea, RightTag :=> eb]
906907
908+filterEventKey
909+ :: forall t m k v a.
910+ ( Reflex t
911+ , MonadFix m
912+ , MonadHold t m
913+ , GEq k
914+ )
915+ => k a
916+ -> Event t (DSum k v)
917+ -> m (Event t (v a))
918+filterEventKey k kv' = do
919+ let f :: DSum k v -> Maybe (v a)
920+ f (newK :=> newV) = case newK `geq` k of
921+ Just Refl -> Just newV
922+ Nothing -> Nothing
923+ takeWhileJustE f kv'
924+
925+
907926factorEvent
908927 :: forall t m k v a.
909928 ( Reflex t
@@ -916,20 +935,13 @@ factorEvent
916935 -> m (Event t (v a), Event t (DSum k (Product v (Compose (Event t) v))))
917936factorEvent k0 kv' = do
918937 key :: Behavior t (Some k) <- hold (Some.This k0) $ fmapCheap (\(k :=> _) -> Some.This k) kv'
919− let inner :: forall m' b. (MonadFix m', MonadHold t m') => k b -> m' (Event t (v b))
920− inner k = do
921− let f :: DSum k v -> Maybe (v b)
922− f (newK :=> newV) = case newK `geq` k of
923− Just Refl -> Just newV
924− Nothing -> Nothing
925− takeWhileJustE f kv'
926− update = flip push kv' $ \(newKey :=> newVal) -> sample key >>= \case
938+ let update = flip push kv' $ \(newKey :=> newVal) -> sample key >>= \case
927939 Some.This oldKey -> case newKey `geq` oldKey of
928940 Just Refl -> return Nothing
929941 Nothing -> do
930− newInner <- inner newKey
942+ newInner <- filterEventKey newKey kv'
931943 return $ Just $ newKey :=> Pair newVal (Compose newInner)
932− eInitial <- inner k0
944+ eInitial <- filterEventKey k0 kv'
933945 return (eInitial, update)
934946
935947--------------------------------------------------------------------------------
src/Reflex/Dynamic.hs+14−10
@@ -325,16 +325,20 @@ eitherDyn = fmap (fmap unpack) . factorDyn . fmap eitherToDSum
325325 LeftTag :=> Compose a -> Left $ coerceDynamic a
326326 RightTag :=> Compose b -> Right $ coerceDynamic b
327327
328−factorDyn :: forall t m k v. (Reflex t, MonadFix m, MonadHold t m, GEq k) => Dynamic t (DSum k v) -> m (Dynamic t (DSum k (Compose (Dynamic t) v)))
329−factorDyn d = do
330− k0 :=> v0 <- sample $ current d --TODO: Figure out how to get this to run inside something like the first argument to buildDynamic
331− (initialEvent, update) <- factorEvent k0 $ updated d
332− initialD <- holdDyn v0 initialEvent
333− let f (k :=> Pair v (Compose v')) = do
334− d' <- holdDyn v v'
335− pure $ k :=> Compose d'
336− holdDyn (k0 :=> Compose initialD) $ pushAlwaysCheap f update
337−
328+factorDyn :: forall t m k v. (Reflex t, MonadHold t m, GEq k)
329+ => Dynamic t (DSum k v) -> m (Dynamic t (DSum k (Compose (Dynamic t) v)))
330+factorDyn d = buildDynamic (sample (current d) >>= holdKey) update where
331+ update :: Event t (DSum k (Compose (Dynamic t) v))
332+ update = flip push (updated d) $ \(newKey :=> newVal) -> do
333+ (oldKey :=> _) <- sample (current d)
334+ case newKey `geq` oldKey of
335+ Just Refl -> return Nothing
336+ Nothing -> Just <$> holdKey (newKey :=> newVal)
337+
338+ holdKey (k :=> v) = do
339+ inner' <- filterEventKey k (updated d)
340+ inner <- holdDyn v inner'
341+ return $ k :=> Compose inner
338342--------------------------------------------------------------------------------
339343-- Demux
340344--------------------------------------------------------------------------------
src/Reflex/DynamicWriter/Base.hs+7−1
@@ -9,6 +9,7 @@
99{-# LANGUAGE TupleSections #-}
1010{-# LANGUAGE TypeFamilies #-}
1111{-# LANGUAGE UndecidableInstances #-}
12+{-# LANGUAGE StandaloneDeriving #-}
1213#ifdef USE_REFLEX_OPTIMIZER
1314{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
1415#endif
@@ -85,7 +86,12 @@ mergeDynIncrementalWithMove a = unsafeBuildIncremental (mapM (sample . current)
8586 in Map.differenceWith (\e _ -> Just $ MapWithMove.nodeInfoSetTo Nothing e) pWithNewVals noLongerMovedMap --TODO: Check if any in the second map are not covered?
8687
8788-- | A basic implementation of 'MonadDynamicWriter'.
88−newtype DynamicWriterT t w m a = DynamicWriterT { unDynamicWriterT :: StateT [Dynamic t w] m a } deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadHold t, MonadSample t, MonadAsyncException, MonadException) -- The list is kept in reverse order
89+newtype DynamicWriterT t w m a = DynamicWriterT { unDynamicWriterT :: StateT [Dynamic t w] m a }
90+ deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadAsyncException, MonadException) -- The list is kept in reverse order
91+
92+deriving instance MonadHold t m => MonadHold t (DynamicWriterT t w m)
93+deriving instance MonadSample t m => MonadSample t (DynamicWriterT t w m)
94+
8995
9096instance MonadRef m => MonadRef (DynamicWriterT t w m) where
9197 type Ref (DynamicWriterT t w m) = Ref m
src/Reflex/Query/Base.hs+6−1
@@ -8,6 +8,8 @@
88{-# LANGUAGE ScopedTypeVariables #-}
99{-# LANGUAGE TypeFamilies #-}
1010{-# LANGUAGE UndecidableInstances #-}
11+{-# LANGUAGE StandaloneDeriving #-}
12+
1113module Reflex.Query.Base
1214 ( QueryT (..)
1315 , runQueryT
@@ -50,7 +52,10 @@ import Reflex.Requester.Class
5052import Reflex.TriggerEvent.Class
5153
5254newtype QueryT t q m a = QueryT { unQueryT :: StateT [Behavior t q] (EventWriterT t q (ReaderT (Dynamic t (QueryResult q)) m)) a }
53− deriving (Functor, Applicative, Monad, MonadException, MonadFix, MonadIO, MonadHold t, MonadSample t, MonadAtomicRef)
55+ deriving (Functor, Applicative, Monad, MonadException, MonadFix, MonadIO, MonadAtomicRef)
56+
57+deriving instance MonadHold t m => MonadHold t (QueryT t q m)
58+deriving instance MonadSample t m => MonadSample t (QueryT t q m)
5459
5560runQueryT :: (MonadFix m, Additive q, Group q, Reflex t) => QueryT t q m a -> Dynamic t (QueryResult q) -> m (a, Incremental t (AdditivePatch q))
5661runQueryT (QueryT a) qr = do
src/Reflex/Spider/Internal.hs+19−8
@@ -1135,7 +1135,11 @@ instance HasSpiderTimeline x => Align (Event x) where
11351135 nil = eventNever
11361136 align ea eb = fmapMaybe dmapToThese $ merge $ dynamicConst $ DMap.fromDistinctAscList [LeftTag :=> ea, RightTag :=> eb]
11371137
1138−newtype Dyn x p = Dyn { unDyn :: IORef (Either (BehaviorM x (PatchTarget p), Event x p) (Hold x p)) }
1138+data DynType x p = UnsafeDyn !(BehaviorM x (PatchTarget p), Event x p)
1139+ | BuildDyn !(EventM x (PatchTarget p), Event x p)
1140+ | HoldDyn !(Hold x p)
1141+
1142+newtype Dyn x p = Dyn { unDyn :: IORef (DynType x p) }
11391143
11401144newMapDyn :: HasSpiderTimeline x => (a -> b) -> Dynamic x (Identity a) -> Dynamic x (Identity b)
11411145newMapDyn f d = dynamicDynIdentity $ unsafeBuildDynamic (fmap f $ readBehaviorTracked $ dynamicCurrent d) (Identity . f . runIdentity <$> dynamicUpdated d)
@@ -1156,15 +1160,15 @@ zipDynWith f da db =
11561160 return $ Just $ Identity $ f a b
11571161 in dynamicDynIdentity $ unsafeBuildDynamic (f <$> readBehaviorUntracked (dynamicCurrent da) <*> readBehaviorUntracked (dynamicCurrent db)) ec
11581162
1159−buildDynamic :: (Defer (SomeDynInit x) m, Patch p) => BehaviorM x (PatchTarget p) -> Event x p -> m (Dyn x p)
1163+buildDynamic :: (Defer (SomeDynInit x) m, Patch p) => EventM x (PatchTarget p) -> Event x p -> m (Dyn x p)
11601164buildDynamic readV0 v' = do
1161− result <- liftIO $ newIORef $ Left (readV0, v')
1165+ result <- liftIO $ newIORef $ BuildDyn (readV0, v')
11621166 let !d = Dyn result
11631167 defer $ SomeDynInit d
11641168 return d
11651169
11661170unsafeBuildDynamic :: BehaviorM x (PatchTarget p) -> Event x p -> Dyn x p
1167−unsafeBuildDynamic readV0 v' = Dyn $ unsafeNewIORef x $ Left x
1171+unsafeBuildDynamic readV0 v' = Dyn $ unsafeNewIORef x $ UnsafeDyn x
11681172 where x = (readV0, v')
11691173
11701174-- ResultM can read behaviors and events
@@ -1374,14 +1378,21 @@ getDynHold :: (Defer (SomeHoldInit x) m, Patch p) => Dyn x p -> m (Hold x p)
13741378getDynHold d = do
13751379 mh <- liftIO $ readIORef $ unDyn d
13761380 case mh of
1377− Right h -> return h
1378− Left (readV0, v') -> do
1381+ HoldDyn h -> return h
1382+ UnsafeDyn (readV0, v') -> do
13791383 holdInits <- getDeferralQueue
13801384 v0 <- liftIO $ runBehaviorM readV0 Nothing holdInits
1385+ hold' v0 v'
1386+ BuildDyn (readV0, v') -> do
1387+ v0 <- liftIO $ runEventM readV0
1388+ hold' v0 v'
1389+ where
1390+ hold' v0 v' = do
13811391 h <- hold v0 v'
1382− liftIO $ writeIORef (unDyn d) $ Right h
1392+ liftIO $ writeIORef (unDyn d) $ HoldDyn h
13831393 return h
13841394
1395+
13851396-- Always refers to 0
13861397{-# NOINLINE zeroRef #-}
13871398zeroRef :: IORef Height
@@ -2317,7 +2328,7 @@ holdDynSpiderEventM v0 e = fmap (SpiderDynamic . dynamicHoldIdentity) $ Reflex.S
23172328holdIncrementalSpiderEventM :: (HasSpiderTimeline x, Patch p) => PatchTarget p -> Reflex.Class.Event (SpiderTimeline x) p -> EventM x (Reflex.Class.Incremental (SpiderTimeline x) p)
23182329holdIncrementalSpiderEventM v0 e = fmap (SpiderIncremental . dynamicHold) $ Reflex.Spider.Internal.hold v0 $ unSpiderEvent e
23192330
2320−buildDynamicSpiderEventM :: HasSpiderTimeline x => SpiderPullM x a -> Reflex.Class.Event (SpiderTimeline x) a -> EventM x (Reflex.Class.Dynamic (SpiderTimeline x) a)
2331+buildDynamicSpiderEventM :: HasSpiderTimeline x => SpiderPushM x a -> Reflex.Class.Event (SpiderTimeline x) a -> EventM x (Reflex.Class.Dynamic (SpiderTimeline x) a)
23212332buildDynamicSpiderEventM getV0 e = fmap (SpiderDynamic . dynamicDynIdentity) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) $ coerce $ unSpiderEvent e
23222333
23232334instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (SpiderHost x) where
test/Reflex/Test/CrossImpl.hs+3
@@ -230,6 +230,9 @@ testCases =
230230 rec result <- holdUniqDyn d
231231 d <- holdDyn (0 :: Int) e
232232 return (current result, updated result)
233+
234+
235+
233236 {-
234237 , (,) "mergeIncrementalWithMove" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, PatchDMapWithMove.moveDMapKey LeftTag RightTag), (2, mempty)]) $ \(b, e :: Event t (PatchDMapWithMove (EitherTag () ()) (Const2 () ()))) -> do
235238 x <- holdIncremental (DMap.singleton LeftTag $ void e) $ PatchDMapWithMove.mapPatchDMapWithMove (\(Const2 _) -> void e) <$> e
test/Reflex/Test/Micro.hs+64−3
@@ -3,6 +3,7 @@
33{-# LANGUAGE FlexibleContexts #-}
44{-# LANGUAGE FlexibleInstances #-}
55{-# LANGUAGE GADTs #-}
6+{-# LANGUAGE ScopedTypeVariables #-}
67{-# LANGUAGE MultiParamTypeClasses #-}
78{-# LANGUAGE RankNTypes #-}
89{-# LANGUAGE RecursiveDo #-}
@@ -23,6 +24,24 @@ import Data.Monoid
2324
2425import Prelude
2526
27+pushDyn :: (Reflex t, MonadHold t m) => (a -> PushM t b) -> Dynamic t a -> m (Dynamic t b)
28+pushDyn f d = buildDynamic (sample (current d) >>= f) (pushAlways f (updated d))
29+
30+foldedDyn :: (Reflex t, MonadHold t m) => (a -> a -> a) -> Dynamic t a -> m (Dynamic t a)
31+foldedDyn f d = fmap join $ flip buildDynamic never $ do
32+ a <- sample (current d)
33+ foldDyn f a (updated d)
34+
35+scannedDyn :: (Reflex t, MonadHold t m) => Dynamic t a -> m (Dynamic t [a])
36+scannedDyn = fmap (fmap reverse) . foldedDyn (<>) . fmap pure
37+
38+scanInnerDyns :: (Reflex t, MonadHold t m) => Dynamic t (Dynamic t a) -> m (Dynamic t [a])
39+scanInnerDyns d = do
40+ scans <- scannedDyn d
41+ return (join (fmap distributeListOverDynPure scans))
42+
43+
44+
2645{-# ANN testCases "HLint: ignore Functor law" #-}
2746testCases :: [(String, TestCase)]
2847testCases =
@@ -201,6 +220,14 @@ testCases =
201220 bb <- hold (constant "x") $ pushAlways (const $ hold "a" eo) eo
202221 return $ pull $ sample =<< sample bb
203222
223+
224+ , testB "foldDynWhileFiring" $ do
225+ e <- events1
226+ d <- foldDyn (:) [] $
227+ pushAlways (\a -> foldDyn (:) [a] e) e
228+
229+ return $ current (join (fmap distributeListOverDynPure d))
230+
204231 , testE "joinDyn" $ do
205232 e <- events1
206233 bb <- hold "b" e
@@ -223,6 +250,38 @@ testCases =
223250 d2 <- fmap (fmap (map toUpper)) $ foldDyn (++) "0" =<< events2
224251
225252 return $ current $ zipDynWith (<>) d1 d2
253+
254+ , testB "buildDynamicStrictness" $ do
255+ rec
256+ d'' <- pushDyn return d'
257+ d' <- pushDyn return d
258+ d <- holdDyn "0" =<< events1
259+
260+ _ <- sample (current d'')
261+ return (current d'')
262+
263+ , testB "factorDyn" $ do
264+ d <- holdDyn (Left "a") =<< eithers
265+
266+ eithers <- eitherDyn d
267+ let unFactor = either id id
268+ return $ current (join (fmap unFactor eithers))
269+
270+ , testB "pushDynDeep" $ do
271+ e1 <- events1
272+ e2 <- events2
273+
274+ d1 <- holdDyn "d1" =<< events1
275+ d2 <- holdDyn "d2" =<< events2
276+
277+ d <- flip pushDyn d1 $ \a ->
278+ flip pushDyn d2 $ \b ->
279+ flip pushDyn d1 $ \c ->
280+ return (a <> b <> c)
281+
282+ d' <- pushDyn scanInnerDyns d >>= scanInnerDyns
283+ return $ current d'
284+
226285 , testE "fan-1" $ do
227286 e <- fmap toMap <$> events1
228287 let es = select (fanMap e) . Const2 <$> values
@@ -264,14 +323,18 @@ testCases =
264323 return $ void e
265324 lazyHold
266325
326+
267327 ] where
268328
269329 events1, events2, events3 :: TestPlan t m => m (Event t String)
270330 events1 = plan [(1, "a"), (2, "b"), (5, "c"), (7, "d"), (8, "e")]
271331 events2 = plan [(1, "e"), (3, "d"), (4, "c"), (6, "b"), (7, "a")]
272−
273332 events3 = liftA2 mappend events1 events2
274333
334+ eithers :: TestPlan t m => m (Event t (Either String String))
335+ eithers = plan [(1, Left "e"), (3, Left "d"), (4, Right "c"), (6, Right "b"), (7, Left "a")]
336+
337+
275338 values = "abcde"
276339 toMap str = Map.fromList $ map (\c -> (c, c)) str
277340
@@ -281,5 +344,3 @@ testCases =
281344
282345 deep e = leftmost [e, e]
283346 leftmost2 e1 e2 = leftmost [e1, e2]
284−
285−
test/Test/Run.hs+8
@@ -64,3 +64,11 @@ runApp' :: (t ~ SpiderTimeline Global, m ~ SpiderHost Global)
6464runApp' app input = do
6565 let app' = fmap (AppOut (pure ())) . app
6666 map (map snd) <$> runApp (app' . _appIn_event) () (map (fmap That) input)
67+
68+runAppB :: (t ~ SpiderTimeline Global, m ~ SpiderHost Global)
69+ => (Event t eIn -> PerformEventT t m (Behavior t bOut))
70+ -> [Maybe eIn]
71+ -> IO [[bOut]]
72+runAppB app input = do
73+ let app' = fmap (flip AppOut never) . app
74+ map (map fst) <$> runApp (app' . _appIn_event) () (map (fmap That) input)
test/semantics.hs−2
@@ -45,5 +45,3 @@ main = do
4545 ]
4646
4747 makeGroup name tests = first (\test -> intercalate "/" [name, test]) <$> tests
48−
49−