on develop help sign in
Merge pull request #69 from lspitzner/develop

Add .gitignore for cabal; Add `unlessE`; Update Quickref.md a bit

commit50d298cb1b5ed850ec017e2aab10ffa1fb5466b0 authorRyan Trinkle <ryan.trinkle@gmail.com> dateTue 18 Oct 2016, 19:52 (10 years ago) parent32c726a5d9ce23
5 files changed+59−15
.gitignore+2 Quickref.md+17−10 src/Reflex/Class.hs+32−2 src/Reflex/Spider/Internal.hs+3−3 test/Reflex/Test/Micro.hs+5
.gitignore+2
@@ -1,4 +1,6 @@
11dist
2+cabal.sandbox.config
3+.cabal-sandbox/
24cabal-dev
35*.o
46*.hi
Quickref.md+17−10
@@ -48,17 +48,22 @@ Since MonadHold depends on MonadSample, any [S] function also runs in [H] contex
4848[ ] attachPromptlyDynWithMaybe :: (a -> b -> Maybe c) -> Dynamic a -> Event b -> Event c
4949
5050-- Combine multiple Events
51−[ ] <> :: Monoid a => Event a -> Event a -> Event a
52−[ ] mergeWith :: (a -> a -> a) -> [Event a] -> Event a
53−[ ] leftmost :: [Event a] -> Event a
54−[ ] mergeList :: [Event a] -> Event (NonEmpty a)
55−[ ] merge :: GCompare k => DMap (WrapArg Event k) -> Event (DMap k)
56−[ ] mergeMap :: Ord k => Map k (Event a) -> Event (Map k a)
51+[ ] <> :: Semigroup a => Event a -> Event a -> Event a
52+[ ] difference :: Event a -> Event b -> Event a
53+[ ] align :: Event a -> Event b -> Event (These a b)
54+[ ] alignWith :: (These a b -> c) -> Event a -> Event b -> Event c
55+[ ] mergeWith :: (a -> a -> a) -> [Event a] -> Event a
56+[ ] leftmost :: [Event a] -> Event a
57+[ ] mergeList :: [Event a] -> Event (NonEmpty a)
58+[ ] merge :: GCompare k => DMap (WrapArg Event k) -> Event (DMap k)
59+[ ] mergeMap :: Ord k => Map k (Event a) -> Event (Map k a)
5760
5861-- Efficient one-to-many fanout
59−[ ] fanMap :: Ord k => Event (Map k a) -> EventSelector (Const2 k a)
60−[ ] fan :: GCompare k => Event (DMap k) -> EventSelector k
61−[ ] select :: EventSelector k -> k a -> Event a
62+[ ] fanMap :: Ord k => Event (Map k a) -> EventSelector (Const2 k a)
63+[ ] fan :: GCompare k => Event (DMap k) -> EventSelector k
64+[ ] select :: EventSelector k -> k a -> Event a
65+[ ] fanEither :: Event (Either a b) -> (Event a, Event b)
66+[ ] fanThese :: Event (These a b) -> (Event a, Event b)
6267
6368-- Event to Event via function that can sample current values
6469[ ] push :: (a -> m (Maybe b)) -> Event a -> Event b
@@ -124,7 +129,9 @@ Since MonadHold depends on MonadSample, any [S] function also runs in [H] contex
124129-- Combine multiple Dynamics
125130[ ] mconcat :: Monoid a => [Dynamic a] -> Dynamic a
126131[ ] distributeDMapOverDynPure :: GCompare k => DMap (WrapArg Dynamic k) -> Dynamic (DMap k)
127−[ ] zipDynWith :: (a -> b -> c) -> Dynamic a -> Dynamic b -> Dynamic c
132+[ ] <*> :: Dynamic (a -> b) -> Dynamic a -> Dynamic b
133+[ ] >>= :: Dynamic a -> (a -> Dynamic b) -> Dynamic b
134+[ ] zipDynWith :: (a -> b -> c) -> Dynamic a -> Dynamic b -> Dynamic c
128135
129136-- Efficient one-to-many fanout
130137[ ] demux :: Ord k => Dynamic k -> Demux k
src/Reflex/Class.hs+32−2
@@ -34,6 +34,7 @@ module Reflex.Class
3434 , mergeMap
3535 , mergeList
3636 , mergeWith
37+ , difference
3738 -- ** Breaking up 'Event's
3839 , splitE
3940 , fanEither
@@ -408,8 +409,21 @@ instance (Reflex t, Semigroup a) => Semigroup (Behavior t a) where
408409#endif
409410
410411--TODO: See if there's a better class in the standard libraries already
412+
411413-- | A class for values that combines filtering and mapping using 'Maybe'.
412−class FunctorMaybe f where
414+-- Morally, @'FunctorMaybe' ~ KleisliFunctor 'Maybe'@. Also similar is the
415+-- @Witherable@ typeclass, but it requires @Foldable f@ and @Traverable f@,
416+-- and e.g. 'Event' is instance of neither.
417+--
418+-- A definition of 'fmapMaybe' must satisfy the following laws:
419+--
420+-- [/identity/]
421+-- @'fmapMaybe' 'Just' ≡ 'id'@
422+--
423+-- [/composition/]
424+-- @'fmapMaybe' (f <=< g) ≡ 'fmapMaybe' f . 'fmapMaybe' g@
425+
426+class Functor f => FunctorMaybe f where
413427 -- | Combined mapping and filtering function.
414428 fmapMaybe :: (a -> Maybe b) -> f a -> f b
415429
@@ -640,7 +654,7 @@ switchPromptly ea0 eea = do
640654
641655instance Reflex t => Align (Event t) where
642656 nil = never
643− align ea eb = fmapMaybe dmapToThese $ merge $ DMap.fromList [LeftTag :=> ea, RightTag :=> eb]
657+ align = alignWithMaybe Just
644658
645659-- | Create a new 'Event' that only occurs if the supplied 'Event' occurs and
646660-- the 'Behavior' is true at the time of occurence.
@@ -660,6 +674,7 @@ zipDyn = zipDynWith (,)
660674
661675-- | Combine two 'Dynamic's with a combining function. The result will change
662676-- whenever either (or both) input 'Dynamic' changes.
677+-- More efficient than liftA2.
663678zipDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Dynamic t b -> Dynamic t c
664679zipDynWith f da db =
665680 let eab = align (updated da) (updated db)
@@ -703,6 +718,21 @@ distributeListOverDyn = distributeListOverDynWith id
703718distributeListOverDynWith :: Reflex t => ([a] -> b) -> [Dynamic t a] -> Dynamic t b
704719distributeListOverDynWith f = fmap (f . map (\(Const2 _ :=> Identity v) -> v) . DMap.toList) . distributeDMapOverDynPure . DMap.fromList . map (\(k, v) -> Const2 k :=> v) . zip [0 :: Int ..]
705720
721+-- | Create a new 'Event' that occurs when the first supplied 'Event' occurs
722+-- unless the second supplied 'Event' occurs simultaneously.
723+difference :: Reflex t => Event t a -> Event t b -> Event t a
724+difference = alignWithMaybe $ \case
725+ This a -> Just a
726+ _ -> Nothing
727+
728+-- (intentially not exported, for now)
729+alignWithMaybe
730+ :: Reflex t => (These a b -> Maybe c) -> Event t a -> Event t b -> Event t c
731+alignWithMaybe f ea eb =
732+ fmapMaybe (f <=< dmapToThese)
733+ $ merge
734+ $ DMap.fromList [LeftTag :=> ea, RightTag :=> eb]
735+
706736
707737--------------------------------------------------------------------------------
708738-- Accumulator
src/Reflex/Spider/Internal.hs+3−3
@@ -840,10 +840,10 @@ instance Functor (Dynamic Identity) where
840840 fmap = newMapDyn
841841
842842instance Applicative (Dynamic Identity) where
843− pure = DynamicConst
843+ pure = DynamicConst
844844 (<*>) = zipDynWith ($)
845− _ *> b = b
846− a <* _ = a
845+ (*>) = zipDynWith (flip const)
846+ (<*) = zipDynWith const
847847
848848instance R.FunctorMaybe Event where
849849 fmapMaybe f = push $ return . f
test/Reflex/Test/Micro.hs+5
@@ -242,6 +242,11 @@ testCases =
242242 f <- fanMap . fmap toMap <$> events1
243243 return $ toList <$> mergeList [ select f (Const2 'b'), select f (Const2 'b'), select f (Const2 'e'), select f (Const2 'e') ]
244244
245+ , testE "difference" $ do
246+ e1 <- events1
247+ e2 <- events2
248+ return $ e1 `difference ` e2
249+
245250 ] where
246251
247252 events1, events2, events3 :: TestPlan t m => m (Event t String)