on develop help sign in
Deprecate FunctorMaybe in favor of Filterable
commitbef906e8a916b2c73152183a5236feb7f4ac5c64 authorAli Abrar <aliabrar@gmail.com> dateSun 17 Mar 2019, 00:55 (8 years ago) parent28b7fde
8 files changed+73−63
default.nix+2−2 reflex.cabal+2−1 src/Data/AppendMap.hs+6−5 src/Reflex/Class.hs+49−28 src/Reflex/FunctorMaybe.hs+6−19 src/Reflex/Requester/Base.hs+2−2 src/Reflex/Spider/Internal.hs+5−5 src/Reflex/Time.hs+1−1
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+2−1
@@ -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
@@ -31,9 +31,10 @@ import qualified Data.Map.Internal.Debug as Map (showTree, showTreeWith)
3131#else
3232import qualified Data.Map as Map (showTree, showTreeWith)
3333#endif
34−import Data.Map.Monoidal
35−import Reflex.Class (FunctorMaybe (..))
3634import Reflex.Patch (Additive, Group (..))
35+import Data.Map.Monoidal hiding (mapMaybe)
36+import qualified Data.Map.Monoidal as M
37+import Data.Witherable (Filterable(..))
3738
3839{-# DEPRECATED AppendMap "Use 'MonoidalMap' instead" #-}
3940type AppendMap = MonoidalMap
@@ -45,8 +46,8 @@ _unAppendMap = getMonoidalMap
4546pattern AppendMap :: Map k v -> MonoidalMap k v
4647pattern AppendMap m = MonoidalMap m
4748
48−instance FunctorMaybe (MonoidalMap k) where
49− fmapMaybe = mapMaybe
49+instance Filterable (MonoidalMap k) where
50+ mapMaybe = M.mapMaybe
5051
5152-- | Deletes a key, returning 'Nothing' if the result is empty.
5253nonEmptyDelete :: Ord k => k -> MonoidalMap k a -> Maybe (MonoidalMap k a)
@@ -60,7 +61,7 @@ mapMaybeNoNull :: (a -> Maybe b)
6061 -> MonoidalMap token a
6162 -> Maybe (MonoidalMap token b)
6263mapMaybeNoNull f as =
63− let bs = fmapMaybe f as
64+ let bs = mapMaybe f as
6465 in if null bs
6566 then Nothing
6667 else Just bs
src/Reflex/Class.hs+49−28
@@ -133,8 +133,9 @@ module Reflex.Class
133133 -- * Unsafe functions
134134 , unsafeDynamic
135135 , unsafeMapIncremental
136− -- * 'FunctorMaybe'
137− , FunctorMaybe (..)
136+ -- * 'Filterable' convenience functions
137+ , FunctorMaybe -- fmapMaybe is purposely not exported from deprecated 'FunctorMaybe' and the new alias is exported instead
138+ , fmapMaybe
138139 , fforMaybe
139140 , ffilter
140141 , filterLeft
@@ -147,6 +148,7 @@ module Reflex.Class
147148 , appendEvents
148149 , onceE
149150 , sequenceThese
151+ , mapMaybeCheap
150152 , fmapMaybeCheap
151153 , fmapCheap
152154 , fforCheap
@@ -193,7 +195,10 @@ import qualified Data.Some as Some
193195import Data.String
194196import Data.These
195197import Data.Type.Coercion
196−import Reflex.FunctorMaybe
198+import Data.Witherable (Filterable(..))
199+import qualified Data.Witherable as W
200+import Reflex.FunctorMaybe (FunctorMaybe)
201+import qualified Reflex.FunctorMaybe
197202import Reflex.Patch
198203import qualified Reflex.Patch.MapWithMove as PatchMapWithMove
199204
@@ -388,8 +393,8 @@ mapAccumMaybeMIncremental f z e = do
388393 return $ case result of
389394 (Nothing, Nothing) -> Nothing
390395 _ -> Just result
391− d' <- holdIncremental z $ fmapMaybe fst e'
392− return (d', fmapMaybe snd e')
396+ d' <- holdIncremental z $ mapMaybe fst e'
397+ return (d', mapMaybe snd e')
393398
394399slowHeadE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
395400slowHeadE e = do
@@ -399,14 +404,14 @@ slowHeadE e = do
399404
400405-- | An 'EventSelector' allows you to efficiently 'select' an 'Event' based on a
401406-- key. This is much more efficient than filtering for each key with
402−-- 'fmapMaybe'.
407+-- 'mapMaybe'.
403408newtype EventSelector t k = EventSelector
404409 { -- | Retrieve the 'Event' for the given key. The type of the 'Event' is
405410 -- determined by the type of the key, so this can be used to fan-out
406411 -- 'Event's whose sub-'Event's have different types.
407412 --
408413 -- Using 'EventSelector's and the 'fan' primitive is far more efficient than
409− -- (but equivalent to) using 'fmapMaybe' to select only the relevant
414+ -- (but equivalent to) using 'mapMaybe' to select only the relevant
410415 -- occurrences of an 'Event'.
411416 select :: forall a. k a -> Event t a
412417 }
@@ -550,22 +555,25 @@ instance (Reflex t, Semigroup a) => Semigroup (Behavior t a) where
550555 times1p n = fmap $ times1p n
551556#endif
552557
553−-- | Flipped version of 'fmapMaybe'.
554−fforMaybe :: FunctorMaybe f => f a -> (a -> Maybe b) -> f b
555−fforMaybe = flip fmapMaybe
558+-- | Alias for 'mapMaybe'
559+fmapMaybe :: Filterable f => (a -> Maybe b) -> f a -> f b
560+fmapMaybe = mapMaybe
561+
562+-- | Flipped version of 'mapMaybe'.
563+fforMaybe :: Filterable f => f a -> (a -> Maybe b) -> f b
564+fforMaybe = flip mapMaybe
556565
557566-- | Filter 'f a' using the provided predicate.
558−-- Relies on 'fforMaybe'.
559−ffilter :: FunctorMaybe f => (a -> Bool) -> f a -> f a
560−ffilter f = fmapMaybe $ \x -> if f x then Just x else Nothing
567+ffilter :: Filterable f => (a -> Bool) -> f a -> f a
568+ffilter = W.filter
561569
562570-- | Filter 'Left's from 'f (Either a b)' into 'a'.
563−filterLeft :: FunctorMaybe f => f (Either a b) -> f a
564−filterLeft = fmapMaybe (either Just (const Nothing))
571+filterLeft :: Filterable f => f (Either a b) -> f a
572+filterLeft = mapMaybe (either Just (const Nothing))
565573
566574-- | Filter 'Right's from 'f (Either a b)' into 'b'.
567−filterRight :: FunctorMaybe f => f (Either a b) -> f b
568−filterRight = fmapMaybe (either (const Nothing) Just)
575+filterRight :: Filterable f => f (Either a b) -> f b
576+filterRight = mapMaybe (either (const Nothing) Just)
569577
570578-- | Left-biased event union (prefers left event on simultaneous
571579-- occurrence).
@@ -583,13 +591,18 @@ instance Reflex t => Bind (Event t) where
583591
584592instance Reflex t => Functor (Event t) where
585593 {-# INLINE fmap #-}
586− fmap f = fmapMaybe $ Just . f
594+ fmap f = mapMaybe $ Just . f
587595 {-# INLINE (<$) #-}
588596 x <$ e = fmapCheap (const x) e
589597
598+-- TODO Remove this instance
590599instance Reflex t => FunctorMaybe (Event t) where
591600 {-# INLINE fmapMaybe #-}
592− fmapMaybe f = push $ return . f
601+ fmapMaybe = mapMaybe
602+
603+instance Reflex t => Filterable (Event t) where
604+ {-# INLINE mapMaybe #-}
605+ mapMaybe f = push $ return . f
593606
594607-- | Never: @'zero' = 'never'@.
595608instance Reflex t => Plus (Event t) where
@@ -807,7 +820,7 @@ fanEither :: Reflex t => Event t (Either a b) -> (Event t a, Event t b)
807820fanEither e =
808821 let justLeft = either Just (const Nothing)
809822 justRight = either (const Nothing) Just
810− in (fmapMaybe justLeft e, fmapMaybe justRight e)
823+ in (mapMaybe justLeft e, mapMaybe justRight e)
811824
812825-- | Split the event into separate events for 'This' and 'That' values,
813826-- allowing them to fire simultaneously when the input value is 'These'.
@@ -819,7 +832,7 @@ fanThese e =
819832 that (That y) = Just y
820833 that (These _ y) = Just y
821834 that _ = Nothing
822− in (fmapMaybe this e, fmapMaybe that e)
835+ in (mapMaybe this e, mapMaybe that e)
823836
824837-- | Split the event into an 'EventSelector' that allows efficient selection of
825838-- the individual 'Event's.
@@ -1002,9 +1015,11 @@ difference = alignEventWithMaybe $ \case
10021015
10031016alignEventWithMaybe :: Reflex t => (These a b -> Maybe c) -> Event t a -> Event t b -> Event t c
10041017alignEventWithMaybe f ea eb =
1005− fmapMaybe (f <=< dmapToThese)
1018+ mapMaybe (f <=< dmapToThese)
10061019 $ merge
10071020 $ DMap.fromList [LeftTag :=> ea, RightTag :=> eb]
1021+alignEventWithMaybe f ea eb = mapMaybe (f <=< dmapToThese) $
1022+ merge $ DMap.fromList [LeftTag :=> ea, RightTag :=> eb]
10081023
10091024filterEventKey
10101025 :: forall t m k v a.
@@ -1100,8 +1115,8 @@ mapAccumMaybeMDyn f z e = do
11001115 return $ case result of
11011116 (Nothing, Nothing) -> Nothing
11021117 _ -> Just result
1103− d' <- holdDyn z $ fmapMaybe fst e'
1104− return (d', fmapMaybe snd e')
1118+ d' <- holdDyn z $ mapMaybe fst e'
1119+ return (d', mapMaybe snd e')
11051120
11061121{-# INLINE accumB #-}
11071122accumB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> a) -> a -> Event t b -> m (Behavior t a)
@@ -1139,8 +1154,8 @@ mapAccumMaybeMB f z e = do
11391154 return $ case result of
11401155 (Nothing, Nothing) -> Nothing
11411156 _ -> Just result
1142− d' <- hold z $ fmapMaybe fst e'
1143− return (d', fmapMaybe snd e')
1157+ d' <- hold z $ mapMaybe fst e'
1158+ return (d', mapMaybe snd e')
11441159
11451160-- | Accumulate occurrences of an 'Event', producing an output occurrence each
11461161-- time. Discard the underlying 'Accumulator'.
@@ -1288,13 +1303,19 @@ infixl 4 <@
12881303pushAlwaysCheap :: Reflex t => (a -> PushM t b) -> Event t a -> Event t b
12891304pushAlwaysCheap f = pushCheap (fmap Just . f)
12901305
1306+{-# INLINE mapMaybeCheap #-}
1307+mapMaybeCheap :: Reflex t => (a -> Maybe b) -> Event t a -> Event t b
1308+mapMaybeCheap f = pushCheap $ return . f
1309+
1310+-- | An alias for 'mapMaybeCheap'
12911311{-# INLINE fmapMaybeCheap #-}
12921312fmapMaybeCheap :: Reflex t => (a -> Maybe b) -> Event t a -> Event t b
1293−fmapMaybeCheap f = pushCheap $ return . f
1313+fmapMaybeCheap = mapMaybeCheap
1314+
12941315
12951316{-# INLINE fforMaybeCheap #-}
12961317fforMaybeCheap :: Reflex t => Event t a -> (a -> Maybe b) -> Event t b
1297−fforMaybeCheap = flip fmapMaybeCheap
1318+fforMaybeCheap = flip mapMaybeCheap
12981319
12991320{-# INLINE fforCheap #-}
13001321fforCheap :: Reflex t => Event t a -> (a -> b) -> Event t b
src/Reflex/FunctorMaybe.hs+6−19
@@ -9,46 +9,33 @@ module Reflex.FunctorMaybe
99 ) where
1010
1111import Data.IntMap (IntMap)
12−import qualified Data.IntMap as IntMap
1312import Data.Map (Map)
14−import qualified Data.Map as Map
15−import Data.Maybe
1613#if MIN_VERSION_base(4,9,0)
1714import Data.Semigroup (Option(..))
1815#endif
16+import Data.Witherable
1917
2018--TODO: See if there's a better class in the standard libraries already
2119
2220-- | A class for values that combines filtering and mapping using 'Maybe'.
23−-- Morally, @'FunctorMaybe' ~ KleisliFunctor 'Maybe'@. Also similar is the
24−-- @Witherable@ typeclass, but it requires @'Foldable' f@ and @'Traversable' f@,
25−-- and e.g. 'Event' is instance of neither.
26−--
27−-- A definition of 'fmapMaybe' must satisfy the following laws:
28−--
29−-- [/identity/]
30−-- @'fmapMaybe' 'Just' ≡ 'id'@
31−--
32−-- [/composition/]
33−-- @'fmapMaybe' (f <=< g) ≡ 'fmapMaybe' f . 'fmapMaybe' g@
21+-- Morally, @'FunctorMaybe' ~ KleisliFunctor 'Maybe'@.
22+{-# DEPRECATED FunctorMaybe "Use 'Filterable' from Data.Witherable instead" #-}
3423class FunctorMaybe f where
3524 -- | Combined mapping and filtering function.
3625 fmapMaybe :: (a -> Maybe b) -> f a -> f b
3726
38−-- | @fmapMaybe = (=<<)
3927instance FunctorMaybe Maybe where
40− fmapMaybe = (=<<)
28+ fmapMaybe = mapMaybe
4129
4230#if MIN_VERSION_base(4,9,0)
4331deriving instance FunctorMaybe Option
4432#endif
4533
46−-- | @fmapMaybe = mapMaybe@
4734instance FunctorMaybe [] where
4835 fmapMaybe = mapMaybe
4936
5037instance FunctorMaybe (Map k) where
51− fmapMaybe = Map.mapMaybe
38+ fmapMaybe = mapMaybe
5239
5340instance FunctorMaybe IntMap where
54− fmapMaybe = IntMap.mapMaybe
41+ fmapMaybe = mapMaybe
src/Reflex/Requester/Base.hs+2−2
@@ -378,7 +378,7 @@ traverseIntMapWithKeyWithAdjustRequesterTWith base patchNewElements mergePatchIn
378378 pack = Entry
379379 f' :: IntMap.Key -> (Int, v) -> m (Event t (IntMap (RequesterData request)), v')
380380 f' k (n, v) = do
381− (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?
381+ (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?
382382 return (fmapCheap (IntMap.singleton n) myRequests, result)
383383 ndm' <- numberOccurrencesFrom 1 dm'
384384 (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
@@ -426,7 +426,7 @@ traverseDMapWithKeyWithAdjustRequesterTWith base mapPatch weakenPatchWith patchN
426426 pack = Entry
427427 f' :: forall a. k a -> Compose ((,) Int) v a -> m (Compose ((,) (Event t (IntMap (RequesterData request)))) v' a)
428428 f' k (Compose (n, v)) = do
429− (result, myRequests) <- runRequesterT (f k v) $ fmapMaybeCheap (IntMap.lookup n) $ select responses (Const2 (Some.This k))
429+ (result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ select responses (Const2 (Some.This k))
430430 return $ Compose (fmapCheap (IntMap.singleton n) myRequests, result)
431431 ndm' <- numberOccurrencesFrom 1 dm'
432432 (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)
src/Reflex/Time.hs+1−1
@@ -28,7 +28,7 @@ import Control.Monad.IO.Class
2828import Data.Align
2929import Data.Data (Data)
3030import Data.Fixed
31−import Data.Semigroup
31+import Data.Semigroup ((<>))
3232import Data.Sequence (Seq, (|>))
3333import qualified Data.Sequence as Seq
3434import Data.These