on develop help sign in
Merge pull request #295 from reflex-frp/aa-haddock-coverage
376cdedAli Abrar
src/Data/AppendMap.hs+14−4
@@ -7,10 +7,14 @@
7{-# LANGUAGE ScopedTypeVariables #-}
7{-# LANGUAGE ScopedTypeVariables #-}
8{-# LANGUAGE TypeFamilies #-}
8{-# LANGUAGE TypeFamilies #-}
9{-# OPTIONS_GHC -fno-warn-orphans #-}
9{-# OPTIONS_GHC -fno-warn-orphans #-}
10−-- | 'Data.Map' with a better 'Monoid' instance
10+-- |
11−--
11+-- Module:
12+-- Data.AppendMap
13+-- Description:
14+-- Instances and convenience functions for 'Data.Map.Monoidal'. We use
15+-- monoidal-containers to take advantage of its better monoid instance.
12−-- 'Data.Map' has @mappend = union@, which is left-biased. AppendMap has
16+-- 'Data.Map' has @mappend = union@, which is left-biased. 'MonoidalMap'
13−-- @mappend = unionWith mappend@ instead.
17+-- has @mappend = unionWith mappend@ instead.
14module Data.AppendMap
18module Data.AppendMap
15 ( module Data.AppendMap
19 ( module Data.AppendMap
16 , module Data.Map.Monoidal
20 , module Data.Map.Monoidal
@@ -30,12 +34,15 @@ import qualified Data.Witherable as W
30import Data.Map.Monoidal
34import Data.Map.Monoidal
31
35
32{-# DEPRECATED AppendMap "Use 'MonoidalMap' instead" #-}
36{-# DEPRECATED AppendMap "Use 'MonoidalMap' instead" #-}
37+-- | AppendMap is a synonym for 'Data.Map.Monoidal.MonoidalMap'
33type AppendMap = MonoidalMap
38type AppendMap = MonoidalMap
34
39
35{-# DEPRECATED _unAppendMap "Use 'getMonoidalMap' instead" #-}
40{-# DEPRECATED _unAppendMap "Use 'getMonoidalMap' instead" #-}
41+-- | A synonym for 'getMonoidalMap'
36_unAppendMap :: MonoidalMap k v -> Map k v
42_unAppendMap :: MonoidalMap k v -> Map k v
37_unAppendMap = getMonoidalMap
43_unAppendMap = getMonoidalMap
38
44
45+-- | Pattern synonym for 'MonoidalMap'
39pattern AppendMap :: Map k v -> MonoidalMap k v
46pattern AppendMap :: Map k v -> MonoidalMap k v
40pattern AppendMap m = MonoidalMap m
47pattern AppendMap m = MonoidalMap m
41
48
@@ -50,6 +57,7 @@ nonEmptyDelete k vs =
50 then Nothing
57 then Nothing
51 else Just deleted
58 else Just deleted
52
59
60+-- | Like 'mapMaybe' but indicates whether the resulting container is empty
53mapMaybeNoNull :: (a -> Maybe b)
61mapMaybeNoNull :: (a -> Maybe b)
54 -> MonoidalMap token a
62 -> MonoidalMap token a
55 -> Maybe (MonoidalMap token b)
63 -> Maybe (MonoidalMap token b)
@@ -60,9 +68,11 @@ mapMaybeNoNull f as =
60 else Just bs
68 else Just bs
61
69
62-- TODO: Move instances to `Reflex.Patch`
70-- TODO: Move instances to `Reflex.Patch`
71+-- | Displays a 'MonoidalMap' as a tree. See 'Data.Map.Lazy.showTree' for details.
63showTree :: forall k a. (Show k, Show a) => MonoidalMap k a -> String
72showTree :: forall k a. (Show k, Show a) => MonoidalMap k a -> String
64showTree = coerce (Map.showTree :: Map k a -> String)
73showTree = coerce (Map.showTree :: Map k a -> String)
65
74
75+-- | Displays a 'MonoidalMap' as a tree, using the supplied function to convert nodes to string.
66showTreeWith :: forall k a. (k -> a -> String) -> Bool -> Bool -> MonoidalMap k a -> String
76showTreeWith :: forall k a. (k -> a -> String) -> Bool -> Bool -> MonoidalMap k a -> String
67showTreeWith = coerce (Map.showTreeWith :: (k -> a -> String) -> Bool -> Bool -> Map k a -> String)
77showTreeWith = coerce (Map.showTreeWith :: (k -> a -> String) -> Bool -> Bool -> Map k a -> String)
68
78
src/Data/FastMutableIntMap.hs+17
@@ -1,4 +1,9 @@
1{-# LANGUAGE TypeFamilies #-}
1{-# LANGUAGE TypeFamilies #-}
2+-- |
3+-- Module:
4+-- Data.FastMutableIntMap
5+-- Description:
6+-- A mutable version of 'IntMap'
2module Data.FastMutableIntMap
7module Data.FastMutableIntMap
3 ( FastMutableIntMap
8 ( FastMutableIntMap
4 , new
9 , new
@@ -32,33 +37,43 @@ import Data.IORef
32import Reflex.Patch.Class
37import Reflex.Patch.Class
33import Reflex.Patch.IntMap
38import Reflex.Patch.IntMap
34
39
40+-- | A 'FastMutableIntMap' holds a map of values of type @a@ and allows low-overhead modifications via IO.
41+-- Operations on 'FastMutableIntMap' run in IO.
35newtype FastMutableIntMap a = FastMutableIntMap (IORef (IntMap a))
42newtype FastMutableIntMap a = FastMutableIntMap (IORef (IntMap a))
36
43
44+-- | Create a new 'FastMutableIntMap' out of an 'IntMap'
37new :: IntMap a -> IO (FastMutableIntMap a)
45new :: IntMap a -> IO (FastMutableIntMap a)
38new m = FastMutableIntMap <$> newIORef m
46new m = FastMutableIntMap <$> newIORef m
39
47
48+-- | Create a new empty 'FastMutableIntMap'
40newEmpty :: IO (FastMutableIntMap a)
49newEmpty :: IO (FastMutableIntMap a)
41newEmpty = FastMutableIntMap <$> newIORef IntMap.empty
50newEmpty = FastMutableIntMap <$> newIORef IntMap.empty
42
51
52+-- | Insert an element into a 'FastMutableIntMap' at the given key
43insert :: FastMutableIntMap a -> Int -> a -> IO ()
53insert :: FastMutableIntMap a -> Int -> a -> IO ()
44insert (FastMutableIntMap r) k v = modifyIORef' r $ IntMap.insert k v
54insert (FastMutableIntMap r) k v = modifyIORef' r $ IntMap.insert k v
45
55
56+-- | Attempt to lookup an element by key in a 'FastMutableIntMap'
46lookup :: FastMutableIntMap a -> Int -> IO (Maybe a)
57lookup :: FastMutableIntMap a -> Int -> IO (Maybe a)
47lookup (FastMutableIntMap r) k = IntMap.lookup k <$> readIORef r
58lookup (FastMutableIntMap r) k = IntMap.lookup k <$> readIORef r
48
59
60+-- | Runs the provided action over the intersection of a 'FastMutableIntMap' and an 'IntMap'
49forIntersectionWithImmutable_ :: MonadIO m => FastMutableIntMap a -> IntMap b -> (a -> b -> m ()) -> m ()
61forIntersectionWithImmutable_ :: MonadIO m => FastMutableIntMap a -> IntMap b -> (a -> b -> m ()) -> m ()
50forIntersectionWithImmutable_ (FastMutableIntMap r) b f = do
62forIntersectionWithImmutable_ (FastMutableIntMap r) b f = do
51 a <- liftIO $ readIORef r
63 a <- liftIO $ readIORef r
52 traverse_ (uncurry f) $ IntMap.intersectionWith (,) a b
64 traverse_ (uncurry f) $ IntMap.intersectionWith (,) a b
53
65
66+-- | Runs the provided action over the values of a 'FastMutableIntMap'
54for_ :: MonadIO m => FastMutableIntMap a -> (a -> m ()) -> m ()
67for_ :: MonadIO m => FastMutableIntMap a -> (a -> m ()) -> m ()
55for_ (FastMutableIntMap r) f = do
68for_ (FastMutableIntMap r) f = do
56 a <- liftIO $ readIORef r
69 a <- liftIO $ readIORef r
57 traverse_ f a
70 traverse_ f a
58
71
72+-- | Checks whether a 'FastMutableIntMap' is empty
59isEmpty :: FastMutableIntMap a -> IO Bool
73isEmpty :: FastMutableIntMap a -> IO Bool
60isEmpty (FastMutableIntMap r) = IntMap.null <$> readIORef r
74isEmpty (FastMutableIntMap r) = IntMap.null <$> readIORef r
61
75
76+-- | Retrieves the size of a 'FastMutableIntMap'
62size :: FastMutableIntMap a -> IO Int
77size :: FastMutableIntMap a -> IO Int
63size (FastMutableIntMap r) = IntMap.size <$> readIORef r
78size (FastMutableIntMap r) = IntMap.size <$> readIORef r
64
79
@@ -69,6 +84,8 @@ getFrozenAndClear (FastMutableIntMap r) = do
69 writeIORef r IntMap.empty
84 writeIORef r IntMap.empty
70 return result
85 return result
71
86
87+-- | Updates the value of a 'FastMutableIntMap' with the given patch (see 'Reflex.Patch.IntMap'),
88+-- and returns an 'IntMap' with the modified keys and values.
72applyPatch :: FastMutableIntMap a -> PatchIntMap a -> IO (IntMap a)
89applyPatch :: FastMutableIntMap a -> PatchIntMap a -> IO (IntMap a)
73applyPatch (FastMutableIntMap r) p@(PatchIntMap m) = do
90applyPatch (FastMutableIntMap r) p@(PatchIntMap m) = do
74 v <- readIORef r
91 v <- readIORef r
src/Data/FastWeakBag.hs+1−1
@@ -50,7 +50,7 @@ newtype FastWeakBag a = FastWeakBag JSVal
50#else
50#else
51data FastWeakBag a = FastWeakBag
51data FastWeakBag a = FastWeakBag
52 { _weakBag_nextId :: {-# UNPACK #-} !(IORef Int) --TODO: what if this wraps around?
52 { _weakBag_nextId :: {-# UNPACK #-} !(IORef Int) --TODO: what if this wraps around?
53− , _weakBag_children :: {-# UNPACK #-} !(IORef (IntMap (Weak a)))
53+ , _weakBag_children :: {-# UNPACK #-} !(IORef (IntMap (Weak a))) -- ^ Map of items contained by the 'FastWeakBag'
54 }
54 }
55#endif
55#endif
56
56
src/Reflex/Adjustable/Class.hs+30−3
@@ -11,6 +11,13 @@
11#ifdef USE_REFLEX_OPTIMIZER
11#ifdef USE_REFLEX_OPTIMIZER
12{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
12{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
13#endif
13#endif
14+-- |
15+-- Module:
16+-- Reflex.Adjustable.Class
17+-- Description:
18+-- A class for actions that can be "adjusted" over time based on some 'Event'
19+-- such that, when observed after the firing of any such 'Event', the result
20+-- is as though the action was originally run with the 'Event's value.
14module Reflex.Adjustable.Class
21module Reflex.Adjustable.Class
15 (
22 (
16 -- * The Adjustable typeclass
23 -- * The Adjustable typeclass
@@ -94,13 +101,32 @@ instance Adjustable t m => Adjustable t (ReaderT r m) where
94 r <- ask
101 r <- ask
95 lift $ traverseDMapWithKeyWithAdjustWithMove (\k v -> runReaderT (f k v) r) dm0 dm'
102 lift $ traverseDMapWithKeyWithAdjustWithMove (\k v -> runReaderT (f k v) r) dm0 dm'
96
103
104+-- | Traverse a 'DMap' of 'Adjustable' actions, running each of them. The provided 'Event' of patches
105+-- to the 'DMap' can add, remove, or update values.
106+sequenceDMapWithAdjust
107+ :: (GCompare k, Adjustable t m)
108+ => DMap k m
109+ -> Event t (PatchDMap k m)
97−sequenceDMapWithAdjust :: (GCompare k, Adjustable t m) => DMap k m -> Event t (PatchDMap k m) -> m (DMap k Identity, Event t (PatchDMap k Identity))
110+ -> m (DMap k Identity, Event t (PatchDMap k Identity))
98sequenceDMapWithAdjust = traverseDMapWithKeyWithAdjust $ \_ -> fmap Identity
111sequenceDMapWithAdjust = traverseDMapWithKeyWithAdjust $ \_ -> fmap Identity
99
112
113+-- | Traverses a 'DMap' of 'Adjustable' actions, running each of them. The provided 'Event' of patches
114+-- to the 'DMap' can add, remove, update, move, or swap values.
115+sequenceDMapWithAdjustWithMove
116+ :: (GCompare k, Adjustable t m)
117+ => DMap k m
118+ -> Event t (PatchDMapWithMove k m)
100−sequenceDMapWithAdjustWithMove :: (GCompare k, Adjustable t m) => DMap k m -> Event t (PatchDMapWithMove k m) -> m (DMap k Identity, Event t (PatchDMapWithMove k Identity))
119+ -> m (DMap k Identity, Event t (PatchDMapWithMove k Identity))
101sequenceDMapWithAdjustWithMove = traverseDMapWithKeyWithAdjustWithMove $ \_ -> fmap Identity
120sequenceDMapWithAdjustWithMove = traverseDMapWithKeyWithAdjustWithMove $ \_ -> fmap Identity
102
121
122+-- | Traverses a 'Map', running the provided 'Adjustable' action. The provided 'Event' of patches to the 'Map'
123+-- can add, remove, update, move, or swap values.
124+mapMapWithAdjustWithMove
125+ :: forall t m k v v'. (Adjustable t m, Ord k)
126+ => (k -> v -> m v')
127+ -> Map k v
128+ -> Event t (PatchMapWithMove k v)
103−mapMapWithAdjustWithMove :: forall t m k v v'. (Adjustable t m, Ord k) => (k -> v -> m v') -> Map k v -> Event t (PatchMapWithMove k v) -> m (Map k v', Event t (PatchMapWithMove k v'))
129+ -> m (Map k v', Event t (PatchMapWithMove k v'))
104mapMapWithAdjustWithMove f m0 m' = do
130mapMapWithAdjustWithMove f m0 m' = do
105 (out0 :: DMap (Const2 k v) (Constant v'), out') <- traverseDMapWithKeyWithAdjustWithMove (\(Const2 k) (Identity v) -> Constant <$> f k v) (mapToDMap m0) (const2PatchDMapWithMoveWith Identity <$> m')
131 (out0 :: DMap (Const2 k v) (Constant v'), out') <- traverseDMapWithKeyWithAdjustWithMove (\(Const2 k) (Identity v) -> Constant <$> f k v) (mapToDMap m0) (const2PatchDMapWithMoveWith Identity <$> m')
106 return (dmapToMapWith (\(Constant v') -> v') out0, patchDMapWithMoveToPatchMapWithMoveWith (\(Constant v') -> v') <$> out')
132 return (dmapToMapWith (\(Constant v') -> v') out0, patchDMapWithMoveToPatchMapWithMoveWith (\(Constant v') -> v') <$> out')
@@ -110,4 +136,5 @@ mapMapWithAdjustWithMove f m0 m' = do
110--------------------------------------------------------------------------------
136--------------------------------------------------------------------------------
111
137
112{-# DEPRECATED MonadAdjust "Use Adjustable instead" #-}
138{-# DEPRECATED MonadAdjust "Use Adjustable instead" #-}
139+-- | Synonym for 'Adjustable'
113type MonadAdjust = Adjustable
140type MonadAdjust = Adjustable
src/Reflex/Class.hs+89−9
@@ -300,6 +300,8 @@ class ( MonadHold t (PushM t)
300 fanInt :: Event t (IntMap a) -> EventSelectorInt t a
300 fanInt :: Event t (IntMap a) -> EventSelectorInt t a
301
301
302--TODO: Specialize this so that we can take advantage of knowing that there's no changing going on
302--TODO: Specialize this so that we can take advantage of knowing that there's no changing going on
303+-- | Constructs a single 'Event' out of a map of events. The output event may fire with multiple
304+-- keys simultaneously.
303mergeInt :: Reflex t => IntMap (Event t a) -> Event t (IntMap a)
305mergeInt :: Reflex t => IntMap (Event t a) -> Event t (IntMap a)
304mergeInt m = mergeIntIncremental $ unsafeBuildIncremental (return m) never
306mergeInt m = mergeIntIncremental $ unsafeBuildIncremental (return m) never
305
307
@@ -368,26 +370,91 @@ class MonadSample t m => MonadHold t m where
368 -- the supplied 'Event'.
370 -- the supplied 'Event'.
369 headE :: Event t a -> m (Event t a)
371 headE :: Event t a -> m (Event t a)
370
372
373+-- | Accumulate an 'Incremental' with the supplied initial value and the firings of the provided 'Event',
374+-- using the combining function to produce a patch.
375+accumIncremental
371−accumIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> p) -> PatchTarget p -> Event t b -> m (Incremental t p)
376+ :: (Reflex t, Patch p, MonadHold t m, MonadFix m)
377+ => (PatchTarget p -> b -> p)
378+ -> PatchTarget p
379+ -> Event t b
380+ -> m (Incremental t p)
372accumIncremental f = accumMaybeIncremental $ \v o -> Just $ f v o
381accumIncremental f = accumMaybeIncremental $ \v o -> Just $ f v o
382+
383+-- | Similar to 'accumIncremental' but the combining function runs in 'PushM'
384+accumMIncremental
373−accumMIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> PushM t p) -> PatchTarget p -> Event t b -> m (Incremental t p)
385+ :: (Reflex t, Patch p, MonadHold t m, MonadFix m)
386+ => (PatchTarget p -> b -> PushM t p)
387+ -> PatchTarget p
388+ -> Event t b
389+ -> m (Incremental t p)
374accumMIncremental f = accumMaybeMIncremental $ \v o -> Just <$> f v o
390accumMIncremental f = accumMaybeMIncremental $ \v o -> Just <$> f v o
391+
392+-- | Similar to 'accumIncremental' but allows filtering of updates (by dropping updates when the
393+-- combining function produces @Nothing@)
394+accumMaybeIncremental
375−accumMaybeIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> Maybe p) -> PatchTarget p -> Event t b -> m (Incremental t p)
395+ :: (Reflex t, Patch p, MonadHold t m, MonadFix m)
396+ => (PatchTarget p -> b -> Maybe p)
397+ -> PatchTarget p
398+ -> Event t b
399+ -> m (Incremental t p)
376accumMaybeIncremental f = accumMaybeMIncremental $ \v o -> return $ f v o
400accumMaybeIncremental f = accumMaybeMIncremental $ \v o -> return $ f v o
401+
402+-- | Similar to 'accumMaybeMIncremental' but the combining function runs in 'PushM'
403+accumMaybeMIncremental
377−accumMaybeMIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> PushM t (Maybe p)) -> PatchTarget p -> Event t b -> m (Incremental t p)
404+ :: (Reflex t, Patch p, MonadHold t m, MonadFix m)
405+ => (PatchTarget p -> b -> PushM t (Maybe p))
406+ -> PatchTarget p
407+ -> Event t b
408+ -> m (Incremental t p)
378accumMaybeMIncremental f z e = do
409accumMaybeMIncremental f z e = do
379 rec let e' = flip push e $ \o -> do
410 rec let e' = flip push e $ \o -> do
380 v <- sample $ currentIncremental d'
411 v <- sample $ currentIncremental d'
381 f v o
412 f v o
382 d' <- holdIncremental z e'
413 d' <- holdIncremental z e'
383 return d'
414 return d'
415+
416+-- | Accumulate an 'Incremental' by folding occurrences of an 'Event'
417+-- with a function that both accumulates and produces a value to fire
418+-- as an 'Event'. Returns both the accumulated value and the constructed
419+-- 'Event'.
420+mapAccumIncremental
384−mapAccumIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> (p, c)) -> PatchTarget p -> Event t b -> m (Incremental t p, Event t c)
421+ :: (Reflex t, Patch p, MonadHold t m, MonadFix m)
422+ => (PatchTarget p -> b -> (p, c))
423+ -> PatchTarget p
424+ -> Event t b
425+ -> m (Incremental t p, Event t c)
385mapAccumIncremental f = mapAccumMaybeIncremental $ \v o -> bimap Just Just $ f v o
426mapAccumIncremental f = mapAccumMaybeIncremental $ \v o -> bimap Just Just $ f v o
427+
428+-- | Like 'mapAccumIncremental' but the combining function runs in 'PushM'
429+mapAccumMIncremental
386−mapAccumMIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> PushM t (p, c)) -> PatchTarget p -> Event t b -> m (Incremental t p, Event t c)
430+ :: (Reflex t, Patch p, MonadHold t m, MonadFix m)
431+ => (PatchTarget p -> b -> PushM t (p, c))
432+ -> PatchTarget p
433+ -> Event t b
434+ -> m (Incremental t p, Event t c)
387mapAccumMIncremental f = mapAccumMaybeMIncremental $ \v o -> bimap Just Just <$> f v o
435mapAccumMIncremental f = mapAccumMaybeMIncremental $ \v o -> bimap Just Just <$> f v o
436+
437+-- | Accumulate an 'Incremental' by folding occurrences of an 'Event' with
438+-- a function that both optionally accumulates and optionally produces
439+-- a value to fire as a separate output 'Event'.
440+-- Note that because 'Nothing's are discarded in both cases, the output
441+-- 'Event' may fire even though the output 'Incremental' has not changed, and
442+-- the output 'Incremental' may update even when the output 'Event' is not firing.
443+mapAccumMaybeIncremental
388−mapAccumMaybeIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> (Maybe p, Maybe c)) -> PatchTarget p -> Event t b -> m (Incremental t p, Event t c)
444+ :: (Reflex t, Patch p, MonadHold t m, MonadFix m)
445+ => (PatchTarget p -> b -> (Maybe p, Maybe c))
446+ -> PatchTarget p
447+ -> Event t b
448+ -> m (Incremental t p, Event t c)
389mapAccumMaybeIncremental f = mapAccumMaybeMIncremental $ \v o -> return $ f v o
449mapAccumMaybeIncremental f = mapAccumMaybeMIncremental $ \v o -> return $ f v o
450+
451+-- | Like 'mapAccumMaybeIncremental' but the combining function is a 'PushM' action
452+mapAccumMaybeMIncremental
390−mapAccumMaybeMIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> PushM t (Maybe p, Maybe c)) -> PatchTarget p -> Event t b -> m (Incremental t p, Event t c)
453+ :: (Reflex t, Patch p, MonadHold t m, MonadFix m)
454+ => (PatchTarget p -> b -> PushM t (Maybe p, Maybe c))
455+ -> PatchTarget p
456+ -> Event t b
457+ -> m (Incremental t p, Event t c)
391mapAccumMaybeMIncremental f z e = do
458mapAccumMaybeMIncremental f z e = do
392 rec let e' = flip push e $ \o -> do
459 rec let e' = flip push e $ \o -> do
393 v <- sample $ currentIncremental d'
460 v <- sample $ currentIncremental d'
@@ -398,6 +465,7 @@ mapAccumMaybeMIncremental f z e = do
398 d' <- holdIncremental z $ mapMaybe fst e'
465 d' <- holdIncremental z $ mapMaybe fst e'
399 return (d', mapMaybe snd e')
466 return (d', mapMaybe snd e')
400
467
468+-- | A somewhat slow implementation of 'headE'
401slowHeadE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
469slowHeadE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
402slowHeadE e = do
470slowHeadE e = do
403 rec be <- hold e $ fmapCheap (const never) e'
471 rec be <- hold e $ fmapCheap (const never) e'
@@ -418,6 +486,8 @@ newtype EventSelector t k = EventSelector
418 select :: forall a. k a -> Event t a
486 select :: forall a. k a -> Event t a
419 }
487 }
420
488
489+-- | Efficiently select an 'Event' keyed on 'Int'. This is more efficient than manually
490+-- filtering by key.
421newtype EventSelectorInt t a = EventSelectorInt { selectInt :: Int -> Event t a }
491newtype EventSelectorInt t a = EventSelectorInt { selectInt :: Int -> Event t a }
422
492
423--------------------------------------------------------------------------------
493--------------------------------------------------------------------------------
@@ -801,7 +871,12 @@ mergeList :: Reflex t => [Event t a] -> Event t (NonEmpty a)
801mergeList [] = never
871mergeList [] = never
802mergeList es = mergeWithFoldCheap' id es
872mergeList es = mergeWithFoldCheap' id es
803
873
874+unsafeMapIncremental
875+ :: (Reflex t, Patch p, Patch p')
804−unsafeMapIncremental :: (Reflex t, Patch p, Patch p') => (PatchTarget p -> PatchTarget p') -> (p -> p') -> Incremental t p -> Incremental t p'
876+ => (PatchTarget p -> PatchTarget p')
877+ -> (p -> p')
878+ -> Incremental t p
879+ -> Incremental t p'
805unsafeMapIncremental f g a = unsafeBuildIncremental (fmap f $ sample $ currentIncremental a) $ g <$> updatedIncremental a
880unsafeMapIncremental f g a = unsafeBuildIncremental (fmap f $ sample $ currentIncremental a) $ g <$> updatedIncremental a
806
881
807-- | Create a new 'Event' combining the map of 'Event's into an 'Event' that
882-- | Create a new 'Event' combining the map of 'Event's into an 'Event' that
@@ -918,6 +993,9 @@ coincidencePatchMapWithMove e = fmapCheap unsafePatchMapWithMove $ coincidence $
918 ni { PatchMapWithMove._nodeInfo_from = PatchMapWithMove.From_Delete }
993 ni { PatchMapWithMove._nodeInfo_from = PatchMapWithMove.From_Delete }
919 ]
994 ]
920
995
996+-- | Given a 'PatchTarget' of events (e.g., a 'Map' with 'Event' values) and an event of 'Patch'es
997+-- (e.g., a 'PatchMap' with 'Event' values), produce an 'Event' of the 'PatchTarget' type that
998+-- fires with the patched value.
921switchHoldPromptOnlyIncremental
999switchHoldPromptOnlyIncremental
922 :: forall t m p pt w
1000 :: forall t m p pt w
923 . ( Reflex t
1001 . ( Reflex t
@@ -1491,8 +1569,10 @@ mergeWithFoldCheap' f es =
1491--------------------------------------------------------------------------------
1569--------------------------------------------------------------------------------
1492
1570
1493{-# DEPRECATED switchPromptly "Use 'switchHoldPromptly' instead. The 'switchHold*' naming convention was chosen because those functions are more closely related to each other than they are to 'switch'. " #-}
1571{-# DEPRECATED switchPromptly "Use 'switchHoldPromptly' instead. The 'switchHold*' naming convention was chosen because those functions are more closely related to each other than they are to 'switch'. " #-}
1572+-- | See 'switchHoldPromptly'
1494switchPromptly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
1573switchPromptly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
1495switchPromptly = switchHoldPromptly
1574switchPromptly = switchHoldPromptly
1496{-# DEPRECATED switchPromptOnly "Use 'switchHoldPromptOnly' instead. The 'switchHold*' naming convention was chosen because those functions are more closely related to each other than they are to 'switch'. " #-}
1575{-# DEPRECATED switchPromptOnly "Use 'switchHoldPromptOnly' instead. The 'switchHold*' naming convention was chosen because those functions are more closely related to each other than they are to 'switch'. " #-}
1576+-- | See 'switchHoldPromptOnly'
1497switchPromptOnly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
1577switchPromptOnly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
1498switchPromptOnly = switchHoldPromptOnly
1578switchPromptOnly = switchHoldPromptOnly
src/Reflex/Dynamic.hs+6
@@ -301,6 +301,8 @@ maybeDyn = fmap (fmap unpack) . eitherDyn . fmap pack
301 Left _ -> Nothing
301 Left _ -> Nothing
302 Right a -> Just a
302 Right a -> Just a
303
303
304+-- | Turns a 'Dynamic t (Either a b)' into a 'Dynamic t (Either (Dynamic t a) (Dynamic t b))' such that
305+-- the outer 'Dynamic' is updated only when the 'Either' constructor changes (e.g., from 'Left' to 'Right').
304eitherDyn :: forall t a b m. (Reflex t, MonadFix m, MonadHold t m) => Dynamic t (Either a b) -> m (Dynamic t (Either (Dynamic t a) (Dynamic t b)))
306eitherDyn :: forall t a b m. (Reflex t, MonadFix m, MonadHold t m) => Dynamic t (Either a b) -> m (Dynamic t (Either (Dynamic t a) (Dynamic t b)))
305eitherDyn = fmap (fmap unpack) . factorDyn . fmap eitherToDSum
307eitherDyn = fmap (fmap unpack) . factorDyn . fmap eitherToDSum
306 where unpack :: DSum (EitherTag a b) (Compose (Dynamic t) Identity) -> Either (Dynamic t a) (Dynamic t b)
308 where unpack :: DSum (EitherTag a b) (Compose (Dynamic t) Identity) -> Either (Dynamic t a) (Dynamic t b)
@@ -308,6 +310,9 @@ eitherDyn = fmap (fmap unpack) . factorDyn . fmap eitherToDSum
308 LeftTag :=> Compose a -> Left $ coerceDynamic a
310 LeftTag :=> Compose a -> Left $ coerceDynamic a
309 RightTag :=> Compose b -> Right $ coerceDynamic b
311 RightTag :=> Compose b -> Right $ coerceDynamic b
310
312
313+-- | Factor a 'Dynamic t DSum' into a 'Dynamic' 'DSum' containing nested 'Dynamic' values.
314+-- The outer 'Dynamic' updates only when the key of the 'DSum' changes, while the update of the inner
315+-- 'Dynamic' represents updates within the current key.
311factorDyn :: forall t m k v. (Reflex t, MonadHold t m, GEq k)
316factorDyn :: forall t m k v. (Reflex t, MonadHold t m, GEq k)
312 => Dynamic t (DSum k v) -> m (Dynamic t (DSum k (Compose (Dynamic t) v)))
317 => Dynamic t (DSum k v) -> m (Dynamic t (DSum k (Compose (Dynamic t) v)))
313factorDyn d = buildDynamic (sample (current d) >>= holdKey) update where
318factorDyn d = buildDynamic (sample (current d) >>= holdKey) update where
@@ -322,6 +327,7 @@ factorDyn d = buildDynamic (sample (current d) >>= holdKey) update where
322 inner' <- filterEventKey k (updated d)
327 inner' <- filterEventKey k (updated d)
323 inner <- holdDyn v inner'
328 inner <- holdDyn v inner'
324 return $ k :=> Compose inner
329 return $ k :=> Compose inner
330+
325--------------------------------------------------------------------------------
331--------------------------------------------------------------------------------
326-- Demux
332-- Demux
327--------------------------------------------------------------------------------
333--------------------------------------------------------------------------------
src/Reflex/DynamicWriter/Class.hs+1
@@ -17,6 +17,7 @@ import Control.Monad.Reader (ReaderT, lift)
17import Reflex.Class (Dynamic)
17import Reflex.Class (Dynamic)
18
18
19{-# DEPRECATED MonadDynamicWriter "Use 'DynamicWriter' instead" #-}
19{-# DEPRECATED MonadDynamicWriter "Use 'DynamicWriter' instead" #-}
20+-- | Type synonym for 'DynamicWriter'
20type MonadDynamicWriter = DynamicWriter
21type MonadDynamicWriter = DynamicWriter
21
22
22-- | 'MonadDynamicWriter' efficiently collects 'Dynamic' values using 'tellDyn'
23-- | 'MonadDynamicWriter' efficiently collects 'Dynamic' values using 'tellDyn'
src/Reflex/Query/Class.hs+24−4
@@ -6,6 +6,13 @@
6{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE TypeFamilies #-}
7{-# LANGUAGE TypeFamilies #-}
8{-# LANGUAGE UndecidableInstances #-}
8{-# LANGUAGE UndecidableInstances #-}
9+-- |
10+-- Module:
11+-- Reflex.Query.Class
12+-- Description:
13+-- A class that ties together queries to some data source and their results,
14+-- providing methods for requesting data from the source and accumulating
15+-- streamed results.
9module Reflex.Query.Class
16module Reflex.Query.Class
10 ( Query (..)
17 ( Query (..)
11 , QueryMorphism (..)
18 , QueryMorphism (..)
@@ -32,6 +39,10 @@ import Foreign.Storable
32
39
33import Reflex.Class
40import Reflex.Class
34
41
42+-- | A 'Query' can be thought of as a declaration of interest in some set of data.
43+-- A 'QueryResult' is the set of data associated with that interest set.
44+-- The @crop@ function provides a way to determine what part of a given 'QueryResult'
45+-- is relevant to a given 'Query'.
35class (Monoid (QueryResult a), Semigroup (QueryResult a)) => Query a where
46class (Monoid (QueryResult a), Semigroup (QueryResult a)) => Query a where
36 type QueryResult a :: *
47 type QueryResult a :: *
37 crop :: a -> QueryResult a -> QueryResult a
48 crop :: a -> QueryResult a -> QueryResult a
@@ -40,8 +51,8 @@ instance (Ord k, Query v) => Query (MonoidalMap k v) where
40 type QueryResult (MonoidalMap k v) = MonoidalMap k (QueryResult v)
51 type QueryResult (MonoidalMap k v) = MonoidalMap k (QueryResult v)
41 crop q r = MonoidalMap.intersectionWith (flip crop) r q
52 crop q r = MonoidalMap.intersectionWith (flip crop) r q
42
53
43−-- | NB: QueryMorphism's must be group homomorphisms when acting on the query type
54+-- | QueryMorphism's must be group homomorphisms when acting on the query type
44−-- and compatible with the query relationship when acting on the query result
55+-- and compatible with the query relationship when acting on the query result.
45data QueryMorphism q q' = QueryMorphism
56data QueryMorphism q q' = QueryMorphism
46 { _queryMorphism_mapQuery :: q -> q'
57 { _queryMorphism_mapQuery :: q -> q'
47 , _queryMorphism_mapQueryResult :: QueryResult q' -> QueryResult q
58 , _queryMorphism_mapQueryResult :: QueryResult q' -> QueryResult q
@@ -54,13 +65,16 @@ instance Category QueryMorphism where
54 , _queryMorphism_mapQueryResult = mapQueryResult qm' . mapQueryResult qm
65 , _queryMorphism_mapQueryResult = mapQueryResult qm' . mapQueryResult qm
55 }
66 }
56
67
68+-- | Apply a 'QueryMorphism' to a 'Query'
57mapQuery :: QueryMorphism q q' -> q -> q'
69mapQuery :: QueryMorphism q q' -> q -> q'
58mapQuery = _queryMorphism_mapQuery
70mapQuery = _queryMorphism_mapQuery
59
71
72+-- | Map a 'QueryMorphism' to a 'QueryResult'
60mapQueryResult :: QueryMorphism q q' -> QueryResult q' -> QueryResult q
73mapQueryResult :: QueryMorphism q q' -> QueryResult q' -> QueryResult q
61mapQueryResult = _queryMorphism_mapQueryResult
74mapQueryResult = _queryMorphism_mapQueryResult
62
75
63−-- | This type keeps track of the multiplicity of elements of the view selector that are being used by the app
76+-- | This type can be used to track of the frequency of interest in a given 'Query'. See note on
77+-- 'combineSelectedCounts'
64newtype SelectedCount = SelectedCount { unSelectedCount :: Int }
78newtype SelectedCount = SelectedCount { unSelectedCount :: Int }
65 deriving (Eq, Ord, Show, Read, Integral, Num, Bounded, Enum, Real, Ix, Bits, FiniteBits, Storable, Data)
79 deriving (Eq, Ord, Show, Read, Integral, Num, Bounded, Enum, Real, Ix, Bits, FiniteBits, Storable, Data)
66
80
@@ -76,10 +90,14 @@ instance Group SelectedCount where
76
90
77instance Additive SelectedCount
91instance Additive SelectedCount
78
92
93+-- | The Semigroup/Monoid/Group instances for a Query containing 'SelectedCount's should use
79−-- | The Semigroup/Monoid/Group instances for a ViewSelector should use this function which returns Nothing if the result is 0. This allows the pruning of leaves that are no longer wanted.
94+-- this function which returns Nothing if the result is 0. This allows the pruning of leaves
95+-- of the 'Query' that are no longer wanted.
80combineSelectedCounts :: SelectedCount -> SelectedCount -> Maybe SelectedCount
96combineSelectedCounts :: SelectedCount -> SelectedCount -> Maybe SelectedCount
81combineSelectedCounts (SelectedCount i) (SelectedCount j) = if i == negate j then Nothing else Just $ SelectedCount (i + j)
97combineSelectedCounts (SelectedCount i) (SelectedCount j) = if i == negate j then Nothing else Just $ SelectedCount (i + j)
82
98
99+-- | A class that allows sending of 'Query's and retrieval of 'QueryResult's. See 'queryDyn' for a commonly
100+-- used interface.
83class (Group q, Additive q, Query q) => MonadQuery t q m | m -> q t where
101class (Group q, Additive q, Query q) => MonadQuery t q m | m -> q t where
84 tellQueryIncremental :: Incremental t (AdditivePatch q) -> m ()
102 tellQueryIncremental :: Incremental t (AdditivePatch q) -> m ()
85 askQueryResult :: m (Dynamic t (QueryResult q))
103 askQueryResult :: m (Dynamic t (QueryResult q))
@@ -90,9 +108,11 @@ instance (Monad m, MonadQuery t q m) => MonadQuery t q (ReaderT r m) where
90 askQueryResult = lift askQueryResult
108 askQueryResult = lift askQueryResult
91 queryIncremental = lift . queryIncremental
109 queryIncremental = lift . queryIncremental
92
110
111+-- | Produce and send an 'Incremental' 'Query' from a 'Dynamic' 'Query'.
93tellQueryDyn :: (Reflex t, MonadQuery t q m) => Dynamic t q -> m ()
112tellQueryDyn :: (Reflex t, MonadQuery t q m) => Dynamic t q -> m ()
94tellQueryDyn d = tellQueryIncremental $ unsafeBuildIncremental (sample (current d)) $ attachWith (\old new -> AdditivePatch $ new ~~ old) (current d) (updated d)
113tellQueryDyn d = tellQueryIncremental $ unsafeBuildIncremental (sample (current d)) $ attachWith (\old new -> AdditivePatch $ new ~~ old) (current d) (updated d)
95
114
115+-- | Retrieve 'Dynamic'ally updating 'QueryResult's for a 'Dynamic'ally updating 'Query'.
96queryDyn :: (Reflex t, Monad m, MonadQuery t q m) => Dynamic t q -> m (Dynamic t (QueryResult q))
116queryDyn :: (Reflex t, Monad m, MonadQuery t q m) => Dynamic t q -> m (Dynamic t (QueryResult q))
97queryDyn q = do
117queryDyn q = do
98 tellQueryDyn q
118 tellQueryDyn q