on develop help sign in
Merge pull request #286 from reflex-frp/aa-deprecate-functormaybe

Deprecate FunctorMaybe in favor of Filterable

commit84ca5e2eb3d230e2ca3cb79c92495244635a51ff authorRyan Trinkle <ryan.trinkle@gmail.com> dateSun 17 Mar 2019, 20:54 (8 years ago) parentbe5e6397ccb414
7 files changed+73−64
default.nix+2−2 reflex.cabal+3−2 src/Data/AppendMap.hs+6−5 src/Reflex/Class.hs+49−29 src/Reflex/FunctorMaybe.hs+6−19 src/Reflex/Requester/Base.hs+2−2 src/Reflex/Spider/Internal.hs+5−5
default.nix+2−2
@@ -6,7 +6,7 @@
66, template-haskell , these, time, transformers
77, transformers-compat, unbounded-delays, prim-uniq
88, data-default, filepath, directory, filemanip, ghcjs-base
9−, monoidal-containers
9+, monoidal-containers, witherable
1010, useTemplateHaskell ? true
1111}:
1212mkDerivation {
@@ -21,7 +21,7 @@ mkDerivation {
2121 transformers-compat prim-uniq
2222 base bifunctors containers deepseq dependent-map dependent-sum
2323 mtl ref-tf split transformers data-default
24− random time unbounded-delays monoidal-containers
24+ random time unbounded-delays monoidal-containers witherable
2525 ] ++ (if ghc.isGhcjs or false then [
2626 ghcjs-base
2727 ] else []) ++ (if !useTemplateHaskell then [] else [
reflex.cabal+3−2
@@ -1,5 +1,5 @@
11Name: reflex
2−Version: 0.5.0.1
2+Version: 0.6
33Synopsis: Higher-order Functional Reactive Programming
44Description: Reflex is a high-performance, deterministic, higher-order Functional Reactive Programming system
55License: BSD3
@@ -64,7 +64,8 @@ library
6464 time >= 1.4 && < 1.9,
6565 transformers >= 0.2,
6666 transformers-compat >= 0.3,
67− unbounded-delays >= 0.1.0.0 && < 0.2
67+ unbounded-delays >= 0.1.0.0 && < 0.2,
68+ witherable >= 0.2 && < 0.4
6869
6970 exposed-modules:
7071 Data.AppendMap,
src/Data/AppendMap.hs+6−5
@@ -26,8 +26,9 @@ import qualified Data.Map.Internal.Debug as Map (showTree, showTreeWith)
2626#else
2727import qualified Data.Map as Map (showTree, showTreeWith)
2828#endif
29−import Data.Map.Monoidal
30−import Reflex.Class (FunctorMaybe (..))
29+import Data.Witherable (Filterable(..))
30+import Data.Map.Monoidal (MonoidalMap(..), delete, null, empty)
31+import qualified Data.Map.Monoidal as M
3132
3233{-# DEPRECATED AppendMap "Use 'MonoidalMap' instead" #-}
3334type AppendMap = MonoidalMap
@@ -39,8 +40,8 @@ _unAppendMap = getMonoidalMap
3940pattern AppendMap :: Map k v -> MonoidalMap k v
4041pattern AppendMap m = MonoidalMap m
4142
42−instance FunctorMaybe (MonoidalMap k) where
43− fmapMaybe = mapMaybe
43+instance Filterable (MonoidalMap k) where
44+ mapMaybe = M.mapMaybe
4445
4546-- | Deletes a key, returning 'Nothing' if the result is empty.
4647nonEmptyDelete :: Ord k => k -> MonoidalMap k a -> Maybe (MonoidalMap k a)
@@ -54,7 +55,7 @@ mapMaybeNoNull :: (a -> Maybe b)
5455 -> MonoidalMap token a
5556 -> Maybe (MonoidalMap token b)
5657mapMaybeNoNull f as =
57− let bs = fmapMaybe f as
58+ let bs = mapMaybe f as
5859 in if null bs
5960 then Nothing
6061 else Just bs
src/Reflex/Class.hs+49−29
@@ -137,8 +137,10 @@ module Reflex.Class
137137 -- * Unsafe functions
138138 , unsafeDynamic
139139 , unsafeMapIncremental
140− -- * 'FunctorMaybe'
141− , FunctorMaybe (..)
140+ -- * 'Filterable' convenience functions
141+ , FunctorMaybe -- fmapMaybe is purposely not exported from deprecated 'FunctorMaybe' and the new alias is exported instead
142+ , mapMaybe -- Re-exported for convenience
143+ , fmapMaybe
142144 , fforMaybe
143145 , ffilter
144146 , filterLeft
@@ -152,6 +154,7 @@ module Reflex.Class
152154 , switchPromptOnly
153155 -- * "Cheap" functions
154156 , fmapMaybeCheap
157+ , mapMaybeCheap
155158 , fmapCheap
156159 , fforCheap
157160 , fforMaybeCheap
@@ -195,7 +198,10 @@ import qualified Data.Some as Some
195198import Data.String
196199import Data.These
197200import Data.Type.Coercion
198−import Reflex.FunctorMaybe
201+import Data.Witherable (Filterable(..))
202+import qualified Data.Witherable as W
203+import Reflex.FunctorMaybe (FunctorMaybe)
204+import qualified Reflex.FunctorMaybe
199205import Reflex.Patch
200206import qualified Reflex.Patch.MapWithMove as PatchMapWithMove
201207
@@ -389,8 +395,8 @@ mapAccumMaybeMIncremental f z e = do
389395 return $ case result of
390396 (Nothing, Nothing) -> Nothing
391397 _ -> Just result
392− d' <- holdIncremental z $ fmapMaybe fst e'
393− return (d', fmapMaybe snd e')
398+ d' <- holdIncremental z $ mapMaybe fst e'
399+ return (d', mapMaybe snd e')
394400
395401slowHeadE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
396402slowHeadE e = do
@@ -400,14 +406,14 @@ slowHeadE e = do
400406
401407-- | An 'EventSelector' allows you to efficiently 'select' an 'Event' based on a
402408-- key. This is much more efficient than filtering for each key with
403−-- 'fmapMaybe'.
409+-- 'mapMaybe'.
404410newtype EventSelector t k = EventSelector
405411 { -- | Retrieve the 'Event' for the given key. The type of the 'Event' is
406412 -- determined by the type of the key, so this can be used to fan-out
407413 -- 'Event's whose sub-'Event's have different types.
408414 --
409415 -- Using 'EventSelector's and the 'fan' primitive is far more efficient than
410− -- (but equivalent to) using 'fmapMaybe' to select only the relevant
416+ -- (but equivalent to) using 'mapMaybe' to select only the relevant
411417 -- occurrences of an 'Event'.
412418 select :: forall a. k a -> Event t a
413419 }
@@ -551,22 +557,25 @@ instance (Reflex t, Semigroup a) => Semigroup (Behavior t a) where
551557 times1p n = fmap $ times1p n
552558#endif
553559
554−-- | Flipped version of 'fmapMaybe'.
555−fforMaybe :: FunctorMaybe f => f a -> (a -> Maybe b) -> f b
556−fforMaybe = flip fmapMaybe
560+-- | Alias for 'mapMaybe'
561+fmapMaybe :: Filterable f => (a -> Maybe b) -> f a -> f b
562+fmapMaybe = mapMaybe
563+
564+-- | Flipped version of 'mapMaybe'.
565+fforMaybe :: Filterable f => f a -> (a -> Maybe b) -> f b
566+fforMaybe = flip mapMaybe
557567
558568-- | Filter 'f a' using the provided predicate.
559−-- Relies on 'fforMaybe'.
560−ffilter :: FunctorMaybe f => (a -> Bool) -> f a -> f a
561−ffilter f = fmapMaybe $ \x -> if f x then Just x else Nothing
569+ffilter :: Filterable f => (a -> Bool) -> f a -> f a
570+ffilter = W.filter
562571
563572-- | Filter 'Left's from 'f (Either a b)' into 'a'.
564−filterLeft :: FunctorMaybe f => f (Either a b) -> f a
565−filterLeft = fmapMaybe (either Just (const Nothing))
573+filterLeft :: Filterable f => f (Either a b) -> f a
574+filterLeft = mapMaybe (either Just (const Nothing))
566575
567576-- | Filter 'Right's from 'f (Either a b)' into 'b'.
568−filterRight :: FunctorMaybe f => f (Either a b) -> f b
569−filterRight = fmapMaybe (either (const Nothing) Just)
577+filterRight :: Filterable f => f (Either a b) -> f b
578+filterRight = mapMaybe (either (const Nothing) Just)
570579
571580-- | Left-biased event union (prefers left event on simultaneous
572581-- occurrence).
@@ -584,13 +593,18 @@ instance Reflex t => Bind (Event t) where
584593
585594instance Reflex t => Functor (Event t) where
586595 {-# INLINE fmap #-}
587− fmap f = fmapMaybe $ Just . f
596+ fmap f = mapMaybe $ Just . f
588597 {-# INLINE (<$) #-}
589598 x <$ e = fmapCheap (const x) e
590599
600+-- TODO Remove this instance
591601instance Reflex t => FunctorMaybe (Event t) where
592602 {-# INLINE fmapMaybe #-}
593− fmapMaybe f = push $ return . f
603+ fmapMaybe = mapMaybe
604+
605+instance Reflex t => Filterable (Event t) where
606+ {-# INLINE mapMaybe #-}
607+ mapMaybe f = push $ return . f
594608
595609-- | Never: @'zero' = 'never'@.
596610instance Reflex t => Plus (Event t) where
@@ -808,7 +822,7 @@ fanEither :: Reflex t => Event t (Either a b) -> (Event t a, Event t b)
808822fanEither e =
809823 let justLeft = either Just (const Nothing)
810824 justRight = either (const Nothing) Just
811− in (fmapMaybe justLeft e, fmapMaybe justRight e)
825+ in (mapMaybe justLeft e, mapMaybe justRight e)
812826
813827-- | Split the event into separate events for 'This' and 'That' values,
814828-- allowing them to fire simultaneously when the input value is 'These'.
@@ -820,7 +834,7 @@ fanThese e =
820834 that (That y) = Just y
821835 that (These _ y) = Just y
822836 that _ = Nothing
823− in (fmapMaybe this e, fmapMaybe that e)
837+ in (mapMaybe this e, mapMaybe that e)
824838
825839-- | Split the event into an 'EventSelector' that allows efficient selection of
826840-- the individual 'Event's.
@@ -1004,7 +1018,7 @@ difference = alignEventWithMaybe $ \case
10041018-- | Zips two values by taking the union of their shapes and combining with the provided function.
10051019-- 'Nothing' values are dropped.
10061020alignEventWithMaybe :: Reflex t => (These a b -> Maybe c) -> Event t a -> Event t b -> Event t c
1007−alignEventWithMaybe f ea eb = fmapMaybe (f <=< dmapToThese) $
1021+alignEventWithMaybe f ea eb = mapMaybe (f <=< dmapToThese) $
10081022 merge $ DMap.fromList [LeftTag :=> ea, RightTag :=> eb]
10091023
10101024-- | Produces an 'Event' that fires only when the input event fires with a 'DSum' key that
@@ -1174,8 +1188,8 @@ mapAccumMaybeMDyn f z e = do
11741188 return $ case result of
11751189 (Nothing, Nothing) -> Nothing
11761190 _ -> Just result
1177− d' <- holdDyn z $ fmapMaybe fst e'
1178− return (d', fmapMaybe snd e')
1191+ d' <- holdDyn z $ mapMaybe fst e'
1192+ return (d', mapMaybe snd e')
11791193
11801194-- | Accumulate a 'Behavior' by folding occurrences of an 'Event'
11811195-- with the provided function.
@@ -1263,8 +1277,8 @@ mapAccumMaybeMB f z e = do
12631277 return $ case result of
12641278 (Nothing, Nothing) -> Nothing
12651279 _ -> Just result
1266− d' <- hold z $ fmapMaybe fst e'
1267− return (d', fmapMaybe snd e')
1280+ d' <- hold z $ mapMaybe fst e'
1281+ return (d', mapMaybe snd e')
12681282
12691283-- | Accumulate occurrences of an 'Event', producing an output occurrence each
12701284-- time. Discard the underlying 'Accumulator'.
@@ -1413,15 +1427,21 @@ infixl 4 <@
14131427pushAlwaysCheap :: Reflex t => (a -> PushM t b) -> Event t a -> Event t b
14141428pushAlwaysCheap f = pushCheap (fmap Just . f)
14151429
1416−-- | A "cheap" version of 'fmapMaybe'. See the performance note on 'pushCheap'.
1430+-- | A "cheap" version of 'mapMaybe'. See the performance note on 'pushCheap'.
1431+{-# INLINE mapMaybeCheap #-}
1432+mapMaybeCheap :: Reflex t => (a -> Maybe b) -> Event t a -> Event t b
1433+mapMaybeCheap f = pushCheap $ return . f
1434+
1435+-- | An alias for 'mapMaybeCheap'
14171436{-# INLINE fmapMaybeCheap #-}
14181437fmapMaybeCheap :: Reflex t => (a -> Maybe b) -> Event t a -> Event t b
1419−fmapMaybeCheap f = pushCheap $ return . f
1438+fmapMaybeCheap = mapMaybeCheap
1439+
14201440
14211441-- | A "cheap" version of 'fforMaybe'. See the performance note on 'pushCheap'.
14221442{-# INLINE fforMaybeCheap #-}
14231443fforMaybeCheap :: Reflex t => Event t a -> (a -> Maybe b) -> Event t b
1424−fforMaybeCheap = flip fmapMaybeCheap
1444+fforMaybeCheap = flip mapMaybeCheap
14251445
14261446-- | A "cheap" version of 'ffor'. See the performance note on 'pushCheap'.
14271447{-# INLINE fforCheap #-}
src/Reflex/FunctorMaybe.hs+6−19
@@ -13,46 +13,33 @@ module Reflex.FunctorMaybe
1313 ) where
1414
1515import Data.IntMap (IntMap)
16−import qualified Data.IntMap as IntMap
1716import Data.Map (Map)
18−import qualified Data.Map as Map
19−import Data.Maybe
2017#if MIN_VERSION_base(4,9,0)
2118import Data.Semigroup (Option(..))
2219#endif
20+import Data.Witherable
2321
2422--TODO: See if there's a better class in the standard libraries already
2523
2624-- | A class for values that combines filtering and mapping using 'Maybe'.
27−-- Morally, @'FunctorMaybe' ~ KleisliFunctor 'Maybe'@. Also similar is the
28−-- @Witherable@ typeclass, but it requires @'Foldable' f@ and @'Traversable' f@,
29−-- and e.g. 'Event' is instance of neither.
30−--
31−-- A definition of 'fmapMaybe' must satisfy the following laws:
32−--
33−-- [/identity/]
34−-- @'fmapMaybe' 'Just' ≡ 'id'@
35−--
36−-- [/composition/]
37−-- @'fmapMaybe' (f <=< g) ≡ 'fmapMaybe' f . 'fmapMaybe' g@
25+-- Morally, @'FunctorMaybe' ~ KleisliFunctor 'Maybe'@.
26+{-# DEPRECATED FunctorMaybe "Use 'Filterable' from Data.Witherable instead" #-}
3827class FunctorMaybe f where
3928 -- | Combined mapping and filtering function.
4029 fmapMaybe :: (a -> Maybe b) -> f a -> f b
4130
42−-- | @fmapMaybe = (=<<)
4331instance FunctorMaybe Maybe where
44− fmapMaybe = (=<<)
32+ fmapMaybe = mapMaybe
4533
4634#if MIN_VERSION_base(4,9,0)
4735deriving instance FunctorMaybe Option
4836#endif
4937
50−-- | @fmapMaybe = mapMaybe@
5138instance FunctorMaybe [] where
5239 fmapMaybe = mapMaybe
5340
5441instance FunctorMaybe (Map k) where
55− fmapMaybe = Map.mapMaybe
42+ fmapMaybe = mapMaybe
5643
5744instance FunctorMaybe IntMap where
58− fmapMaybe = IntMap.mapMaybe
45+ fmapMaybe = mapMaybe
src/Reflex/Requester/Base.hs+2−2
@@ -393,7 +393,7 @@ traverseIntMapWithKeyWithAdjustRequesterTWith base patchNewElements mergePatchIn
393393 pack = Entry
394394 f' :: IntMap.Key -> (Int, v) -> m (Event t (IntMap (RequesterData request)), v')
395395 f' k (n, v) = do
396− (result, myRequests) <- runRequesterT (f k v) $ fmapMaybeCheap (IntMap.lookup n) $ selectInt responses k --TODO: Instead of doing fmapMaybeCheap, can we share a fanInt across all instances of a given key, or at least the ones that are adjacent in time?
396+ (result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ selectInt responses k --TODO: Instead of doing mapMaybeCheap, can we share a fanInt across all instances of a given key, or at least the ones that are adjacent in time?
397397 return (fmapCheap (IntMap.singleton n) myRequests, result)
398398 ndm' <- numberOccurrencesFrom 1 dm'
399399 (children0, children') <- base f' (fmap ((,) 0) dm0) $ fmap (\(n, dm) -> fmap ((,) n) dm) ndm' --TODO: Avoid this somehow, probably by adding some sort of per-cohort information passing to Adjustable
@@ -441,7 +441,7 @@ traverseDMapWithKeyWithAdjustRequesterTWith base mapPatch weakenPatchWith patchN
441441 pack = Entry
442442 f' :: forall a. k a -> Compose ((,) Int) v a -> m (Compose ((,) (Event t (IntMap (RequesterData request)))) v' a)
443443 f' k (Compose (n, v)) = do
444− (result, myRequests) <- runRequesterT (f k v) $ fmapMaybeCheap (IntMap.lookup n) $ select responses (Const2 (Some.This k))
444+ (result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ select responses (Const2 (Some.This k))
445445 return $ Compose (fmapCheap (IntMap.singleton n) myRequests, result)
446446 ndm' <- numberOccurrencesFrom 1 dm'
447447 (children0, children') <- base f' (DMap.map (\v -> Compose (0, v)) dm0) $ fmap (\(n, dm) -> mapPatch (\v -> Compose (n, v)) dm) ndm'
src/Reflex/Spider/Internal.hs+5−5
@@ -49,16 +49,16 @@ import Data.GADT.Compare
4949import Data.IntMap.Strict (IntMap)
5050import qualified Data.IntMap.Strict as IntMap
5151import Data.IORef
52−import Data.Maybe
52+import Data.Maybe hiding (mapMaybe)
5353import Data.Monoid ((<>))
5454import Data.Proxy
5555import Data.These
5656import Data.Traversable
57+import Data.Witherable (Filterable, mapMaybe)
5758import GHC.Exts
5859import GHC.IORef (IORef (..))
5960import GHC.Stack
6061import Reflex.FastWeak
61−import Reflex.FunctorMaybe
6262import System.IO.Unsafe
6363import System.Mem.Weak
6464import Unsafe.Coerce
@@ -1128,12 +1128,12 @@ newInvalidatorSwitch subd = return $! InvalidatorSwitch subd
11281128newInvalidatorPull :: Pull x a -> IO (Invalidator x)
11291129newInvalidatorPull p = return $! InvalidatorPull p
11301130
1131−instance HasSpiderTimeline x => FunctorMaybe (Event x) where
1132− fmapMaybe f = push $ return . f
1131+instance HasSpiderTimeline x => Filterable (Event x) where
1132+ mapMaybe f = push $ return . f
11331133
11341134instance HasSpiderTimeline x => Align (Event x) where
11351135 nil = eventNever
1136− align ea eb = fmapMaybe dmapToThese $ merge $ dynamicConst $ DMap.fromDistinctAscList [LeftTag :=> ea, RightTag :=> eb]
1136+ align ea eb = mapMaybe dmapToThese $ merge $ dynamicConst $ DMap.fromDistinctAscList [LeftTag :=> ea, RightTag :=> eb]
11371137
11381138data DynType x p = UnsafeDyn !(BehaviorM x (PatchTarget p), Event x p)
11391139 | BuildDyn !(EventM x (PatchTarget p), Event x p)