@@ -7,6 +7,7 @@ import Reflex.TestPlan
8import Control.Monad.Fix
8import Control.Monad.Fix
9import Control.Monad
9import Control.Monad
10+import Control.Monad.Identity
10import Control.Applicative
11import Control.Applicative
11import Data.Foldable
12import Data.Foldable
12import Data.Traversable
13import Data.Traversable
@@ -14,6 +15,9 @@ import Data.Traversable
14import Data.Maybe
15import Data.Maybe
15import Data.Map (Map)
16import Data.Map (Map)
16import qualified Data.Map as Map
17import qualified Data.Map as Map
18+import qualified Data.Dependent.Map as DMap
20+import Data.Functor.Misc
18import Data.Tuple
22import Data.Tuple
19import Data.List
23import Data.List
@@ -21,6 +25,7 @@ import Data.List.Split
22import Prelude
26import Prelude
24mergeTree :: Num a => (Monoid (f [a]), Functor f) => Int -> [f a] -> f a
29mergeTree :: Num a => (Monoid (f [a]), Functor f) => Int -> [f a] -> f a
25mergeTree n es | length es <= n = sum' es
30mergeTree n es | length es <= n = sum' es
26 | otherwise = mergeTree n subTrees
31 | otherwise = mergeTree n subTrees
@@ -39,6 +44,8 @@ mergeTreeDyn n dyns | length dyns <= n = sumDyns dyns
39 merges = chunksOf n dyns
44 merges = chunksOf n dyns
40 sumDyns ds = mergeListDyn ds >>= mapDyn sum
45 sumDyns ds = mergeListDyn ds >>= mapDyn sum
42-- N events all firing for N frames
49-- N events all firing for N frames
43continuous :: TestPlan t m => Word -> Word -> m [Event t Word]
50continuous :: TestPlan t m => Word -> Word -> m [Event t Word]
44continuous n frames = for [1..n] $ \i -> plan $ (, i) <$> [1..frames]
51continuous n frames = for [1..n] $ \i -> plan $ (, i) <$> [1..frames]
@@ -50,10 +57,13 @@ occasional n period frames = traverse plan $ zipWith occs [1..] phases
50 phases = take (fromIntegral n) $ concat (repeat [1..period])
57 phases = take (fromIntegral n) $ concat (repeat [1..period])
51 occs i phase = (, i) <$> [1, phase+1..frames]
58 occs i phase = (, i) <$> [1, phase+1..frames]
53-- Event which never fires (but isn't 'never')
62-- Event which never fires (but isn't 'never')
54never' :: TestPlan t m => m (Event t Word)
63never' :: TestPlan t m => m (Event t Word)
55never' = plan []
64never' = plan []
57-- Event which fires once on first frame
67-- Event which fires once on first frame
58event :: TestPlan t m => m (Event t Word)
68event :: TestPlan t m => m (Event t Word)
59event = plan [(1, 0)]
69event = plan [(1, 0)]
@@ -62,30 +72,53 @@ event = plan [(1, 0)]
62events :: TestPlan t m => Word -> m (Event t Word)
72events :: TestPlan t m => Word -> m (Event t Word)
63events n = plan $ (\i -> (i, i)) <$> [1..n]
73events n = plan $ (\i -> (i, i)) <$> [1..n]
65-- N events all originating from one event
76-- N events all originating from one event
66fmapFan :: Reflex t => Word -> Event t Word -> [Event t Word]
77fmapFan :: Reflex t => Word -> Event t Word -> [Event t Word]
67fmapFan n e = (\i -> (+i) <$> e) <$> [1..n]
78fmapFan n e = (\i -> (+i) <$> e) <$> [1..n]
81+-- Make a fan using the value in the event converting it to a singleton Map
82+-- use a fan of size n (key is the value mod n)
83+fanMerge :: Reflex t => Word -> Event t Word -> Event t Word
84+fanMerge n e = leftmost $ s <$> [0..n - 1] where
85+ s k = select f (Const2 k)
86+ f = fan (toMap <$> e)
87+ toMap k = DMap.singleton (Const2 $ k `mod` n) (Identity k)
89+-- Dumb version of the above using simple fmapMaybe to filter
90+fmapFanMerge :: Reflex t => Word -> Event t Word -> Event t Word
91+fmapFanMerge n e = leftmost $ s <$> [0..n - 1] where
92+ s k = flip fmapMaybe e $ \j -> if (k == j `mod` n)
69-- Create an Event with a Map which is dense to size N
98-- Create an Event with a Map which is dense to size N
70denseMap :: TestPlan t m => Word -> m (Event t (Map Word Word))
99denseMap :: TestPlan t m => Word -> m (Event t (Map Word Word))
71denseMap n = plan [(1, m)] where
100denseMap n = plan [(1, m)] where
72 m = Map.fromList $ zip [1..n] [1..n]
101 m = Map.fromList $ zip [1..n] [1..n]
74−fmapChain :: Reflex t => Word -> Event t Word -> (Event t Word)
103+iter :: (a -> a) -> Word -> a -> a
75−fmapChain 0 e = e
104+iter _ 0 a = a
76−fmapChain n e = fmapChain (n - 1) (fmap (+1) e)
105+iter f n a = iter f (n - 1) (f a)
107+iterM :: Monad m => (a -> m a) -> Word -> a -> m a
108+iterM _ 0 a = return a
109+iterM f n a = iterM f (n - 1) =<< f a
111+fmapChain :: (Functor f) => Word -> f Word -> f Word
112+fmapChain = iter (fmap (+1))
78mapDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
114mapDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
79−mapDynChain 0 d = return d
115+mapDynChain = iterM (mapDyn (+1))
80−mapDynChain n d = mapDynChain (n - 1) =<< mapDyn (+1) d
82joinDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
117joinDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
83−joinDynChain 0 d = return d
84−joinDynChain n d = joinDynChain (n - 1) =<< joinDyn <$> mapDyn (const d) d
118+joinDynChain = iterM (\d -> joinDyn <$> mapDyn (const d) d)
86combineDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
120combineDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
87−combineDynChain 0 d = return d
121+combineDynChain = iterM (\d -> combineDyn (+) d d)
88−combineDynChain n d = combineDynChain (n - 1) =<< combineDyn (+) d d
90pingPong :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> Event t a -> m (Event t a)
123pingPong :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> Event t a -> m (Event t a)
91pingPong e1 e2 = do
124pingPong e1 e2 = do
@@ -100,27 +133,27 @@ switchFactors i e = do
100 b <- hold ((+1) <$> e) (e <$ ffilter ((== 0) . (i `mod`)) e)
133 b <- hold ((+1) <$> e) (e <$ ffilter ((== 0) . (i `mod`)) e)
101 switchFactors (i - 1) (switch b)
134 switchFactors (i - 1) (switch b)
103switchChain :: (Reflex t, MonadHold t m, MonadFix m) => Word -> Event t Word -> m (Event t Word)
137switchChain :: (Reflex t, MonadHold t m, MonadFix m) => Word -> Event t Word -> m (Event t Word)
104−switchChain 0 e = return e
138+switchChain = iterM (\e -> pingPong e ((+1) <$> e))
105−switchChain i e = switchChain (i - 1) =<< pingPong e ((+1) <$> e)
139+
107switchChain2 :: (Reflex t, MonadHold t m, MonadFix m) => Word -> Event t Word -> m (Event t Word)
141switchChain2 :: (Reflex t, MonadHold t m, MonadFix m) => Word -> Event t Word -> m (Event t Word)
108−switchChain2 0 e = return e
109−switchChain2 i e = switchChain2 (i - 1) =<< pingPong e ((+1) <$> leftmost [e, e])
142+switchChain2 = iterM (\e -> pingPong e ((+1) <$> leftmost [e, e]))
111switchPromptlyChain :: (Reflex t, MonadHold t m) => Word -> Event t Word -> m (Event t Word)
144switchPromptlyChain :: (Reflex t, MonadHold t m) => Word -> Event t Word -> m (Event t Word)
112−switchPromptlyChain 0 e = return e
145+switchPromptlyChain = iterM $ \e ->
113−switchPromptlyChain i e = do
114− d <- holdDyn e (e <$ e)
146+ switchPromptlyDyn <$> holdDyn e (e <$ e)
115− switchPromptlyChain (i - 1) (switchPromptlyDyn d)
147+
117coinChain :: Reflex t => Word -> Event t Word -> Event t Word
149coinChain :: Reflex t => Word -> Event t Word -> Event t Word
118−coinChain 0 e = e
150+coinChain = iter $ \e -> coincidence (e <$ e)
119−coinChain n e = coinChain (n - 1) $ coincidence (e <$ e)
151+
152+fanMergeChain :: Reflex t => Word -> Word -> Event t Word -> Event t Word
153+fanMergeChain width = iter $ fanMerge width
121−pullChain :: Reflex t => Word -> Behavior t Word -> Behavior t Word
155+fmapFanMergeChain :: Reflex t => Word -> Word -> Event t Word -> Event t Word
122−pullChain 0 b = b
156+fmapFanMergeChain width = iter $ fmapFanMerge width
123−pullChain n b = pullChain (n - 1) $ (+1) <$> b
125-- | Data type for a collection (a map) which is updated by providing differences
158-- | Data type for a collection (a map) which is updated by providing differences
126data UpdatedMap t k a = UpdatedMap (Map k a) (Event t (Map k (Maybe a)))
159data UpdatedMap t k a = UpdatedMap (Map k a) (Event t (Map k (Maybe a)))
@@ -129,6 +162,9 @@ data UpdatedMap t k a = UpdatedMap (Map k a) (Event t (Map k (Maybe a)))
129switchMergeEvents :: (MonadFix m, MonadHold t m, Reflex t, Ord k) => UpdatedMap t k (Event t a) -> m (Event t (Map k a))
162switchMergeEvents :: (MonadFix m, MonadHold t m, Reflex t, Ord k) => UpdatedMap t k (Event t a) -> m (Event t (Map k a))
130switchMergeEvents mapChanges = switch . fmap mergeMap <$> holdMap mapChanges
163switchMergeEvents mapChanges = switch . fmap mergeMap <$> holdMap mapChanges
165+-- switchMergeMaybe :: (MonadFix m, MonadHold t m, Reflex t, Ord k) => UpdatedMap t k (Event t a) -> m (Event t (Map k a))
166+-- switchMergeMaybe (UpdatedMap initial changes) = switchMergeMap initial (fmap (fromMaybe never) <$> changes)
132switchMergeBehaviors :: forall a t m k. (MonadFix m, MonadHold t m, Reflex t, Ord k) => UpdatedMap t k (Behavior t a) -> m (Behavior t (Map k a))
168switchMergeBehaviors :: forall a t m k. (MonadFix m, MonadHold t m, Reflex t, Ord k) => UpdatedMap t k (Behavior t a) -> m (Behavior t (Map k a))
133switchMergeBehaviors mapChanges = pull <$> joinMap <$> holdMap mapChanges
169switchMergeBehaviors mapChanges = pull <$> joinMap <$> holdMap mapChanges
134 where joinMap m = traverse sample =<< sample m
170 where joinMap m = traverse sample =<< sample m
@@ -136,6 +172,7 @@ switchMergeBehaviors mapChanges = pull <$> joinMap <$> holdMap mapChanges
136-- | Turn an UpdatedMap into a Dynamic by applying the differences to the initial value
172-- | Turn an UpdatedMap into a Dynamic by applying the differences to the initial value
137holdMapDyn :: (Reflex t, MonadHold t m, MonadFix m, Ord k) => UpdatedMap t k a -> m (Dynamic t (Map k a))
173holdMapDyn :: (Reflex t, MonadHold t m, MonadFix m, Ord k) => UpdatedMap t k a -> m (Dynamic t (Map k a))
138holdMapDyn (UpdatedMap initial changes) = foldDyn (flip (Map.foldWithKey modify)) initial changes
174holdMapDyn (UpdatedMap initial changes) = foldDyn (flip (Map.foldWithKey modify)) initial changes
140 modify k Nothing items = Map.delete k items
177 modify k Nothing items = Map.delete k items
141 modify k (Just item) items = Map.insert k item items
178 modify k (Just item) items = Map.insert k item items
@@ -145,6 +182,7 @@ holdMapDyn (UpdatedMap initial changes) = foldDyn (flip (Map.foldWithKey modify)
145holdMap :: (Reflex t, MonadHold t m, MonadFix m, Ord k) => UpdatedMap t k a -> m (Behavior t (Map k a))
182holdMap :: (Reflex t, MonadHold t m, MonadFix m, Ord k) => UpdatedMap t k a -> m (Behavior t (Map k a))
146holdMap = (current <$>) . holdMapDyn
183holdMap = (current <$>) . holdMapDyn
148increasingMerge :: TestPlan t m => [a] -> m (UpdatedMap t Int a)
186increasingMerge :: TestPlan t m => [a] -> m (UpdatedMap t Int a)
149increasingMerge xs = do
187increasingMerge xs = do
150 e <- planList (zipWith Map.singleton [1..] (Just <$> xs) ++ [reset])
188 e <- planList (zipWith Map.singleton [1..] (Just <$> xs) ++ [reset])
@@ -167,34 +205,43 @@ modifyMerge xs = do
168 initial = Map.fromList $ zip [1..] xs
206 initial = Map.fromList $ zip [1..] xs
170countMany :: (Reflex t, MonadHold t m, MonadFix m) => [Event t a] -> m [Behavior t Int]
209countMany :: (Reflex t, MonadHold t m, MonadFix m) => [Event t a] -> m [Behavior t Int]
171countMany = traverse (fmap current . count)
210countMany = traverse (fmap current . count)
173countManyDyn :: (Reflex t, MonadHold t m, MonadFix m) => [Event t a] -> m [Dynamic t Int]
212countManyDyn :: (Reflex t, MonadHold t m, MonadFix m) => [Event t a] -> m [Dynamic t Int]
174countManyDyn = traverse count
213countManyDyn = traverse count
176-- Given a function which creates a sub-network (from a single event)
216-- Given a function which creates a sub-network (from a single event)
177-- Create a plan which uses a switch to substitute it
217-- Create a plan which uses a switch to substitute it
178switches :: TestPlan t m => Word -> (forall n. (MonadHold t n, MonadFix n) => Event t Word -> n (Event t a)) -> m (Event t a)
218switches :: TestPlan t m => Word -> (forall n. (MonadHold t n, MonadFix n) => Event t Word -> n (Event t a)) -> m (Event t a)
179switches numFrames f = do
219switches numFrames f = do
180 es <- events numFrames
220 es <- events numFrames
181 switch <$> hold never (makeEvents es)
221 switch <$> hold never (makeEvents es)
183 makeEvents es = pushAlways (\n -> f (fmap (+n) es)) es
224 makeEvents es = pushAlways (\n -> f (fmap (+n) es)) es
185-- Two sets of benchmarks, one which we're interested in testing subscribe time (as well as time to fire frames)
228-- Two sets of benchmarks, one which we're interested in testing subscribe time (as well as time to fire frames)
186-- the other, which we're only interested in time for running frames
229-- the other, which we're only interested in time for running frames
187subscribing :: Word -> Word -> [(String, TestCase)]
230subscribing :: Word -> Word -> [(String, TestCase)]
188subscribing n frames =
231subscribing n frames =
189− [ testE "fmapFan merge" $ switches frames (return . mergeList . fmapFan n)
232+ [ testSub "fmapFanMerge" $ return . mergeList . fmapFan n
233+ , testSub "fanMerge" $ return . fanMerge n
190− , testE "fmapFan/mergeTree" $ switches frames (return . mergeTree 8 . fmapFan n)
234+ , testSub "fmapFan/mergeTree" $ return . mergeTree 8 . fmapFan n
191− , testE "fmapChain" $ switches frames (return . fmapChain n)
235+ , testSub "fmapChain" $ return . fmapChain n
192− , testE "switchChain" $ switches frames (switchChain n)
236+ , testSub "switchChain" $ switchChain n
193− , testE "switchPromptlyChain" $ switches frames (switchPromptlyChain n)
237+ , testSub "switchPromptlyChain" $ switchPromptlyChain n
194− , testE "switchFactors" $ switches frames (switchFactors n)
238+ , testSub "switchFactors" $ switchFactors n
195− , testE "coincidenceChain" $ switches frames (return . coinChain n)
239+ , testSub "coincidenceChain" $ return . coinChain n
243+ testSub :: (Eq a, Show a) => String -> (forall t n. (Reflex t, MonadHold t n, MonadFix n) => Event t Word -> n (Event t a)) -> (String, TestCase)
244+ testSub name test = testE name (switches frames test)
199-- Set of benchmark to test specifically merging dynamic collections
246-- Set of benchmark to test specifically merging dynamic collections
200-- a pattern which occurs frequently in reflex-dom collections
247-- a pattern which occurs frequently in reflex-dom collections
@@ -209,6 +256,11 @@ merging n =
209 , testB "increasing behaviors" $ switchMergeBehaviors =<< increasingMerge =<< counters
256 , testB "increasing behaviors" $ switchMergeBehaviors =<< increasingMerge =<< counters
210 , testB "decreasing behaviors" $ switchMergeBehaviors =<< decreasingMerge =<< counters
257 , testB "decreasing behaviors" $ switchMergeBehaviors =<< decreasingMerge =<< counters
211 , testB "modify behaviors" $ switchMergeBehaviors =<< modifyMerge =<< counters
258 , testB "modify behaviors" $ switchMergeBehaviors =<< modifyMerge =<< counters
261+ -- , testE "increasing events/switchMerge" $ switchMergeMaybe =<< increasingMerge =<< sparse
262+ -- , testE "decreasing events/switchMerge" $ switchMergeMaybe =<< decreasingMerge =<< sparse
263+ -- , testE "modify events/switchMerge" $ switchMergeMaybe =<< modifyMerge =<< sparse
@@ -218,15 +270,37 @@ merging n =
218 counters :: TestPlan t m => m [Behavior t Int]
270 counters :: TestPlan t m => m [Behavior t Int]
219 counters = countMany =<< sparse
271 counters = countMany =<< sparse
275+fans :: Word -> [(String, TestCase)]
277+ [ testE "fanMapChain" $ fanMergeChain n 10 <$> e
278+ , testE "fmapFanMapChain" $ fmapFanMergeChain n 10 <$> e
280+ , testE "fanMerge " $ fanMerge n <$> events n
282+ , testE "fmapFanMerge " $ fmapFanMerge n <$> events n
283+ , testE "triggerMerge" $ leftmost <$> forM [1..n] (\i -> plan [(i, i)])
288+ e :: TestPlan t m => m (Event t Word)
221dynamics :: Word -> [(String, TestCase)]
294dynamics :: Word -> [(String, TestCase)]
222dynamics n =
295dynamics n =
223 [ testE "mapDynChain" $ fmap updated $ mapDynChain n =<< d
296 [ testE "mapDynChain" $ fmap updated $ mapDynChain n =<< d
224 , testE "joinDynChain" $ fmap updated $ joinDynChain n =<< d
297 , testE "joinDynChain" $ fmap updated $ joinDynChain n =<< d
225 , testE "combineDynChain" $ fmap updated $ combineDynChain n =<< d
298 , testE "combineDynChain" $ fmap updated $ combineDynChain n =<< d
226− , testE "dense mergeTree" $ fmap updated $ mergeTreeDyn 8 =<< dense
299+ , testE "dense mergeTree" $ fmap updated $ mergeTreeDyn 8 =<< dense
227 , testE "sparse mergeTree" $ fmap updated $ mergeTreeDyn 8 =<< sparse
300 , testE "sparse mergeTree" $ fmap updated $ mergeTreeDyn 8 =<< sparse
228 , testE "mergeDyn" $ fmap updated $ mapDyn sum =<< mergeListDyn =<< sparse
301 , testE "mergeDyn" $ fmap updated $ mapDyn sum =<< mergeListDyn =<< sparse
230 d :: TestPlan t m => m (Dynamic t Word)
304 d :: TestPlan t m => m (Dynamic t Word)
231 d = count =<< events 10
305 d = count =<< events 10
@@ -245,20 +319,25 @@ firing n =
246 , testE "dense mergeTree" $ mergeTree 8 <$> dense
320 , testE "dense mergeTree" $ mergeTree 8 <$> dense
247 , testE "sparse mergeTree" $ mergeTree 8 <$> sparse
321 , testE "sparse mergeTree" $ mergeTree 8 <$> sparse
323+ -- Triggers test failure in Spider
248− , testE "runFrame" $ events n
324+ --, testE "runFrame" $ events n
249 , testB "sum counters" $ do
326 , testB "sum counters" $ do
250 counts <- counters
327 counts <- counters
251 return $ pull $ sum <$> traverse sample counts
328 return $ pull $ sum <$> traverse sample counts
253− , testB "pullChain" $ pullChain n . current <$> (count =<< events 4)
330+ , testB "pullChain" $ fmapChain n . current <$> (count =<< events 4)
254 , testB "pullChain2" $ do
331 , testB "pullChain2" $ do
255− e' <- events 4
332+ es <- events 4
256− b <- hold (constant 0) $ leftmost
333+ e <- plan [(0, ())]
257− [ constant 0 <$ ffilter (==4) e'
334+
335+ b <- hold (constant 0) $
258− , pushAlways (const $ pullChain n <$> hold 0 e') e'
336+ pushAlways (const $ fmapChain n <$> hold 0 es) e
260 return (join b)
338 return (join b)
261 , testB "counters/pullTree" $ mergeTree 8 <$> counters
339 , testB "counters/pullTree" $ mergeTree 8 <$> counters
264 e :: TestPlan t m => m (Event t Word)
343 e :: TestPlan t m => m (Event t Word)
@@ -271,3 +350,7 @@ firing n =
271 counters :: TestPlan t m => m [Behavior t Int]
350 counters :: TestPlan t m => m [Behavior t Int]
272 counters = countMany =<< sparse
351 counters = countMany =<< sparse