on develop help sign in
Merge pull request #410 from reflex-frp/release/0.7.0.0
b14cf8aElliot Cameron
ChangeLog.md+9
@@ -1,5 +1,14 @@
1# Revision history for reflex
1# Revision history for reflex
2
2
3+## 0.7.0.0
4+
5+* Add lifting instances for most classes to `Reflex.Profiled.Profiled`. ([#398](https://github.com/reflex-frp/reflex/pull/398))
6+* Class `MonadQuery t q m` now has a `Monad m` superclass constraint. ([#400](https://github.com/reflex-frp/reflex/pull/400))
7+* **(Breaking change)** Rename class `MonadBehaviorWriter` -> `BehaviorWriter` for consistency with `EventWriter`/`DynamicWriter`. ([#401](https://github.com/reflex-frp/reflex/pull/401))
8+* Introduce deprecated alias `MonadBehaviorWriter = BehaviorWriter`. ([#401](https://github.com/reflex-frp/reflex/pull/401))
9+* Fix bug in spider where event subscriptions would be prematurely finalized due to over-aggressive inlining. ([#409](https://github.com/reflex-frp/reflex/pull/409))
10+* Add instances of `PerformEvent` and `TriggerEvent` for `MaybeT`. ([#395](https://github.com/reflex-frp/reflex/pull/395))
11+
3## 0.6.4.1
12## 0.6.4.1
4
13
5* Fix a bug in the Reflex Profiled transformer where
14* Fix a bug in the Reflex Profiled transformer where
README.md+8−2
@@ -21,5 +21,11 @@ A summary of Reflex functions is available in the [quick reference](Quickref.md)
21
21
22### Hacking
22### Hacking
23
23
24+From the root of a [Reflex
24−Use the `./scripts/hack-on reflex` script in [Reflex Platform](https://github.com/reflex-frp/reflex-platform) to checkout the source code of `reflex` locally in `reflex-platform/reflex` directory.
25+Platform](https://github.com/reflex-frp/reflex-platform) checkout, run
26+`./scripts/hack-on haskell-overlays/reflex-packages/dep/reflex`. This
27+will check out the reflex source code into the
28+`haskell-overlays/reflex-packages/dep/reflex` directory. You can then
29+point that checkout at your fork, make changes, etc. Use the
25−Then do modifications to the source in place, and use the `./try-reflex` or `./scripts/work-on` scripts to create the shell to test your changes.
30+`./try-reflex` or `./scripts/work-on` scripts to start a shell in
31+which you can test your changes.
reflex.cabal+1−1
@@ -1,5 +1,5 @@
1Name: reflex
1Name: reflex
2−Version: 0.6.4.1
2+Version: 0.7.0.0
3Synopsis: Higher-order Functional Reactive Programming
3Synopsis: Higher-order Functional Reactive Programming
4Description: Reflex is a high-performance, deterministic, higher-order Functional Reactive Programming system
4Description: Reflex is a high-performance, deterministic, higher-order Functional Reactive Programming system
5License: BSD3
5License: BSD3
src/Reflex/BehaviorWriter/Base.hs+3−3
@@ -1,6 +1,6 @@
1{-|
1{-|
2Module: Reflex.BehaviorWriter.Base
2Module: Reflex.BehaviorWriter.Base
3−Description: Implementation of MonadBehaviorWriter
3+Description: Implementation of BehaviorWriter
4-}
4-}
5{-# LANGUAGE CPP #-}
5{-# LANGUAGE CPP #-}
6{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE FlexibleInstances #-}
@@ -46,7 +46,7 @@ import Reflex.Query.Class
46import Reflex.Requester.Class
46import Reflex.Requester.Class
47import Reflex.TriggerEvent.Class
47import Reflex.TriggerEvent.Class
48
48
49−-- | A basic implementation of 'MonadBehaviorWriter'.
49+-- | A basic implementation of 'BehaviorWriter'.
50newtype BehaviorWriterT t w m a = BehaviorWriterT { unBehaviorWriterT :: StateT [Behavior t w] m a }
50newtype BehaviorWriterT t w m a = BehaviorWriterT { unBehaviorWriterT :: StateT [Behavior t w] m a }
51 deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadAsyncException, MonadException) -- The list is kept in reverse order
51 deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadAsyncException, MonadException) -- The list is kept in reverse order
52
52
@@ -89,7 +89,7 @@ instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (BehaviorWri
89 newEventWithTrigger = lift . newEventWithTrigger
89 newEventWithTrigger = lift . newEventWithTrigger
90 newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
90 newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
91
91
92−instance (Monad m, Monoid w, Reflex t) => MonadBehaviorWriter t w (BehaviorWriterT t w m) where
92+instance (Monad m, Monoid w, Reflex t) => BehaviorWriter t w (BehaviorWriterT t w m) where
93 tellBehavior w = BehaviorWriterT $ modify (w :)
93 tellBehavior w = BehaviorWriterT $ modify (w :)
94
94
95instance MonadReader r m => MonadReader r (BehaviorWriterT t w m) where
95instance MonadReader r m => MonadReader r (BehaviorWriterT t w m) where
src/Reflex/BehaviorWriter/Class.hs+11−5
@@ -1,8 +1,9 @@
1{-|
1{-|
2Module: Reflex.BehaviorWriter.Class
2Module: Reflex.BehaviorWriter.Class
3−Description: This module defines the 'MonadBehaviorWriter' class
3+Description: This module defines the 'BehaviorWriter' class
4-}
4-}
5{-# LANGUAGE CPP #-}
5{-# LANGUAGE CPP #-}
6+{-# LANGUAGE ConstraintKinds #-}
6{-# LANGUAGE FlexibleInstances #-}
7{-# LANGUAGE FlexibleInstances #-}
7{-# LANGUAGE FunctionalDependencies #-}
8{-# LANGUAGE FunctionalDependencies #-}
8{-# LANGUAGE UndecidableInstances #-}
9{-# LANGUAGE UndecidableInstances #-}
@@ -10,16 +11,21 @@ Description: This module defines the 'MonadBehaviorWriter' class
10{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
11{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
11#endif
12#endif
12module Reflex.BehaviorWriter.Class
13module Reflex.BehaviorWriter.Class
13− ( MonadBehaviorWriter (..)
14+ ( MonadBehaviorWriter
15+ , BehaviorWriter(..)
14 ) where
16 ) where
15
17
16import Control.Monad.Reader (ReaderT, lift)
18import Control.Monad.Reader (ReaderT, lift)
17import Reflex.Class (Behavior)
19import Reflex.Class (Behavior)
18
20
21+{-# DEPRECATED MonadBehaviorWriter "Use 'BehaviorWriter' instead" #-}
22+-- | Type synonym for 'BehaviorWriter'
23+type MonadBehaviorWriter = BehaviorWriter
24+
19−-- | 'MonadBehaviorWriter' efficiently collects 'Behavior' values using 'tellBehavior'
25+-- | 'BehaviorWriter' efficiently collects 'Behavior' values using 'tellBehavior'
20-- and combines them monoidally to provide a 'Behavior' result.
26-- and combines them monoidally to provide a 'Behavior' result.
21−class (Monad m, Monoid w) => MonadBehaviorWriter t w m | m -> t w where
27+class (Monad m, Monoid w) => BehaviorWriter t w m | m -> t w where
22 tellBehavior :: Behavior t w -> m ()
28 tellBehavior :: Behavior t w -> m ()
23
29
24−instance MonadBehaviorWriter t w m => MonadBehaviorWriter t w (ReaderT r m) where
30+instance BehaviorWriter t w m => BehaviorWriter t w (ReaderT r m) where
25 tellBehavior = lift . tellBehavior
31 tellBehavior = lift . tellBehavior
src/Reflex/FastWeak.hs+10
@@ -151,6 +151,16 @@ getFastWeakTicket w = do
151
151
152-- | Create a 'FastWeakTicket' directly from a value, creating a 'FastWeak' in the process
152-- | Create a 'FastWeakTicket' directly from a value, creating a 'FastWeak' in the process
153-- which can be obtained with 'getFastWeakTicketValue'.
153-- which can be obtained with 'getFastWeakTicketValue'.
154+--
155+-- This function is marked NOINLINE so it is opaque to GHC.
156+-- If we do not do this, then GHC will sometimes fuse the constructor away
157+-- so any weak references that are attached to the ticket will have their
158+-- finalizer run. Using the opaque constructor, GHC does not see the
159+-- constructor application, so it behaves like an IORef and cannot be fused away.
160+--
161+-- The result is also evaluated to WHNF, since forcing a thunk invalidates
162+-- the weak pointer to it in some cases.
163+{-# NOINLINE mkFastWeakTicket #-}
154mkFastWeakTicket :: a -> IO (FastWeakTicket a)
164mkFastWeakTicket :: a -> IO (FastWeakTicket a)
155-- I think it's fine if this is lazy - it'll retain the 'a', but so would the output; we just need to make sure it's forced before we start relying on the
165-- I think it's fine if this is lazy - it'll retain the 'a', but so would the output; we just need to make sure it's forced before we start relying on the
156-- associated FastWeak to actually be weak
166-- associated FastWeak to actually be weak
src/Reflex/PerformEvent/Class.hs+6
@@ -22,6 +22,7 @@ import Reflex.Class
22import Reflex.TriggerEvent.Class
22import Reflex.TriggerEvent.Class
23
23
24import Control.Monad.Reader
24import Control.Monad.Reader
25+import Control.Monad.Trans.Maybe (MaybeT (..))
25
26
26-- | 'PerformEvent' represents actions that can trigger other actions based on
27-- | 'PerformEvent' represents actions that can trigger other actions based on
27-- 'Event's.
28-- 'Event's.
@@ -61,3 +62,8 @@ instance PerformEvent t m => PerformEvent t (ReaderT r m) where
61 performEvent e = do
62 performEvent e = do
62 r <- ask
63 r <- ask
63 lift $ performEvent $ flip runReaderT r <$> e
64 lift $ performEvent $ flip runReaderT r <$> e
65+
66+instance PerformEvent t m => PerformEvent t (MaybeT m) where
67+ type Performable (MaybeT m) = MaybeT (Performable m)
68+ performEvent_ = lift . performEvent_ . fmapCheap (void . runMaybeT)
69+ performEvent = lift . fmap (fmapMaybe id) . performEvent . fmapCheap runMaybeT
src/Reflex/Profiled.hs+53−1
@@ -26,6 +26,7 @@ import Control.Monad.Primitive
26import Control.Monad.Reader
26import Control.Monad.Reader
27import Control.Monad.Ref
27import Control.Monad.Ref
28import Control.Monad.State.Strict (StateT, execStateT, modify)
28import Control.Monad.State.Strict (StateT, execStateT, modify)
29+import Data.Bifunctor
29import Data.Coerce
30import Data.Coerce
30import Data.Dependent.Map (DMap, GCompare)
31import Data.Dependent.Map (DMap, GCompare)
31import Data.FastMutableIntMap
32import Data.FastMutableIntMap
@@ -42,12 +43,20 @@ import Foreign.Ptr
42import GHC.Foreign
43import GHC.Foreign
43import GHC.IO.Encoding
44import GHC.IO.Encoding
44import GHC.Stack
45import GHC.Stack
46+import Reflex.Adjustable.Class
47+import Reflex.BehaviorWriter.Class
45import Reflex.Class
48import Reflex.Class
49+import Reflex.DynamicWriter.Class
50+import Reflex.EventWriter.Class
46import Reflex.Host.Class
51import Reflex.Host.Class
52+import Reflex.NotReady.Class
47import Reflex.PerformEvent.Class
53import Reflex.PerformEvent.Class
54+import Reflex.PostBuild.Class
55+import Reflex.Query.Class
56+import Reflex.Requester.Class
57+import Reflex.TriggerEvent.Class
48
58
49import System.IO.Unsafe
59import System.IO.Unsafe
50−import Unsafe.Coerce
51
60
52data ProfiledTimeline t
61data ProfiledTimeline t
53
62
@@ -178,6 +187,16 @@ instance MonadHold t m => MonadHold (ProfiledTimeline t) (ProfiledM m) where
178instance MonadSample t m => MonadSample (ProfiledTimeline t) (ProfiledM m) where
187instance MonadSample t m => MonadSample (ProfiledTimeline t) (ProfiledM m) where
179 sample (Behavior_Profiled b) = ProfiledM $ sample b
188 sample (Behavior_Profiled b) = ProfiledM $ sample b
180
189
190+instance Adjustable t m => Adjustable (ProfiledTimeline t) (ProfiledM m) where
191+ runWithReplace a0 a' = (fmap . fmap) coerce . lift $
192+ runWithReplace (coerce a0) (coerce $ coerce <$> a')
193+ traverseIntMapWithKeyWithAdjust f dm0 dm' = (fmap . fmap) coerce . lift $
194+ traverseIntMapWithKeyWithAdjust (\k v -> coerce $ f k v) dm0 (coerce dm')
195+ traverseDMapWithKeyWithAdjust f dm0 dm' = (fmap . fmap) coerce . lift $
196+ traverseDMapWithKeyWithAdjust (\k v -> coerce $ f k v) dm0 (coerce dm')
197+ traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = (fmap . fmap) coerce . lift $
198+ traverseDMapWithKeyWithAdjustWithMove (\k v -> coerce $ f k v) dm0 (coerce dm')
199+
181instance MonadTrans ProfiledM where
200instance MonadTrans ProfiledM where
182 lift = ProfiledM
201 lift = ProfiledM
183
202
@@ -189,6 +208,39 @@ instance PerformEvent t m => PerformEvent (ProfiledTimeline t) (ProfiledM m) whe
189 performEvent_ = lift . performEvent_ . coerce
208 performEvent_ = lift . performEvent_ . coerce
190 performEvent = lift . fmap coerce . performEvent . coerce
209 performEvent = lift . fmap coerce . performEvent . coerce
191
210
211+instance TriggerEvent t m => TriggerEvent (ProfiledTimeline t) (ProfiledM m) where
212+ newTriggerEvent = first coerce <$> lift newTriggerEvent
213+ newTriggerEventWithOnComplete = first coerce <$> lift newTriggerEventWithOnComplete
214+ newEventWithLazyTriggerWithOnComplete f = coerce <$> lift (newEventWithLazyTriggerWithOnComplete f)
215+
216+instance PostBuild t m => PostBuild (ProfiledTimeline t) (ProfiledM m) where
217+ getPostBuild = coerce <$> lift getPostBuild
218+
219+instance NotReady t m => NotReady (ProfiledTimeline t) (ProfiledM m) where
220+ notReady = lift notReady
221+ notReadyUntil = lift . notReadyUntil . coerce
222+
223+instance BehaviorWriter t w m => BehaviorWriter (ProfiledTimeline t) w (ProfiledM m) where
224+ tellBehavior = lift . tellBehavior . coerce
225+
226+instance DynamicWriter t w m => DynamicWriter (ProfiledTimeline t) w (ProfiledM m) where
227+ tellDyn = lift . tellDyn . coerce
228+
229+instance EventWriter t w m => EventWriter (ProfiledTimeline t) w (ProfiledM m) where
230+ tellEvent = lift . tellEvent . coerce
231+
232+instance MonadQuery t q m => MonadQuery (ProfiledTimeline t) q (ProfiledM m) where
233+ tellQueryIncremental = lift . tellQueryIncremental . coerce
234+ askQueryResult = coerce <$> lift askQueryResult
235+ queryIncremental = fmap coerce . lift . queryIncremental . coerce
236+
237+instance Requester t m => Requester (ProfiledTimeline t) (ProfiledM m) where
238+ type Request (ProfiledM m) = Request m
239+ type Response (ProfiledM m) = Response m
240+
241+ requesting = fmap coerce . lift . requesting . coerce
242+ requesting_ = lift . requesting_ . coerce
243+
192instance MonadRef m => MonadRef (ProfiledM m) where
244instance MonadRef m => MonadRef (ProfiledM m) where
193 type Ref (ProfiledM m) = Ref m
245 type Ref (ProfiledM m) = Ref m
194 newRef = lift . newRef
246 newRef = lift . newRef
src/Reflex/Query/Class.hs+5−5
@@ -125,7 +125,7 @@ instance Group SelectedCount where
125
125
126instance Additive SelectedCount
126instance Additive SelectedCount
127
127
128−-- | The Semigroup/Monoid/Group instances for a Query containing 'SelectedCount's should use
128+-- | The Semigroup\/Monoid\/Group instances for a Query containing 'SelectedCount's should use
129-- this function which returns Nothing if the result is 0. This allows the pruning of leaves
129-- this function which returns Nothing if the result is 0. This allows the pruning of leaves
130-- of the 'Query' that are no longer wanted.
130-- of the 'Query' that are no longer wanted.
131combineSelectedCounts :: SelectedCount -> SelectedCount -> Maybe SelectedCount
131combineSelectedCounts :: SelectedCount -> SelectedCount -> Maybe SelectedCount
@@ -133,12 +133,12 @@ combineSelectedCounts (SelectedCount i) (SelectedCount j) = if i == negate j the
133
133
134-- | A class that allows sending of 'Query's and retrieval of 'QueryResult's. See 'queryDyn' for a commonly
134-- | A class that allows sending of 'Query's and retrieval of 'QueryResult's. See 'queryDyn' for a commonly
135-- used interface.
135-- used interface.
136−class (Group q, Additive q, Query q) => MonadQuery t q m | m -> q t where
136+class (Group q, Additive q, Query q, Monad m) => MonadQuery t q m | m -> q t where
137 tellQueryIncremental :: Incremental t (AdditivePatch q) -> m ()
137 tellQueryIncremental :: Incremental t (AdditivePatch q) -> m ()
138 askQueryResult :: m (Dynamic t (QueryResult q))
138 askQueryResult :: m (Dynamic t (QueryResult q))
139 queryIncremental :: Incremental t (AdditivePatch q) -> m (Dynamic t (QueryResult q))
139 queryIncremental :: Incremental t (AdditivePatch q) -> m (Dynamic t (QueryResult q))
140
140
141−instance (Monad m, MonadQuery t q m) => MonadQuery t q (ReaderT r m) where
141+instance MonadQuery t q m => MonadQuery t q (ReaderT r m) where
142 tellQueryIncremental = lift . tellQueryIncremental
142 tellQueryIncremental = lift . tellQueryIncremental
143 askQueryResult = lift askQueryResult
143 askQueryResult = lift askQueryResult
144 queryIncremental = lift . queryIncremental
144 queryIncremental = lift . queryIncremental
@@ -148,11 +148,11 @@ tellQueryDyn :: (Reflex t, MonadQuery t q m) => Dynamic t q -> m ()
148tellQueryDyn d = tellQueryIncremental $ unsafeBuildIncremental (sample (current d)) $ attachWith (\old new -> AdditivePatch $ new ~~ old) (current d) (updated d)
148tellQueryDyn d = tellQueryIncremental $ unsafeBuildIncremental (sample (current d)) $ attachWith (\old new -> AdditivePatch $ new ~~ old) (current d) (updated d)
149
149
150-- | Retrieve 'Dynamic'ally updating 'QueryResult's for a 'Dynamic'ally updating 'Query'.
150-- | Retrieve 'Dynamic'ally updating 'QueryResult's for a 'Dynamic'ally updating 'Query'.
151−queryDyn :: (Reflex t, Monad m, MonadQuery t q m) => Dynamic t q -> m (Dynamic t (QueryResult q))
151+queryDyn :: (Reflex t, MonadQuery t q m) => Dynamic t q -> m (Dynamic t (QueryResult q))
152queryDyn q = do
152queryDyn q = do
153 tellQueryDyn q
153 tellQueryDyn q
154 zipDynWith crop q <$> askQueryResult
154 zipDynWith crop q <$> askQueryResult
155
155
156-- | Use a query morphism to operate on a smaller version of a query.
156-- | Use a query morphism to operate on a smaller version of a query.
157−subQuery :: (Reflex t, MonadQuery t q2 m, Monad m) => QueryMorphism q1 q2 -> Dynamic t q1 -> m (Dynamic t (QueryResult q1))
157+subQuery :: (Reflex t, MonadQuery t q2 m) => QueryMorphism q1 q2 -> Dynamic t q1 -> m (Dynamic t (QueryResult q1))
158subQuery (QueryMorphism f g) x = fmap g <$> queryDyn (fmap f x)
158subQuery (QueryMorphism f g) x = fmap g <$> queryDyn (fmap f x)
src/Reflex/Spider/Internal.hs−10
@@ -450,16 +450,6 @@ data Subscriber x a = Subscriber
450 , subscriberRecalculateHeight :: !(Height -> IO ())
450 , subscriberRecalculateHeight :: !(Height -> IO ())
451 }
451 }
452
452
453−--TODO: Move this comment to WeakBag
454−-- These function are constructor functions that are marked NOINLINE so they are
455−-- opaque to GHC. If we do not do this, then GHC will sometimes fuse the constructor away
456−-- so any weak references that are attached to the constructors will have their
457−-- finalizer run. Using the opaque constructor, does not see the
458−-- constructor application, so it behaves like an IORef and cannot be fused away.
459−--
460−-- The result is also evaluated to WHNF, since forcing a thunk invalidates
461−-- the weak pointer to it in some cases.
462−
463newSubscriberHold :: (HasSpiderTimeline x, Patch p) => Hold x p -> IO (Subscriber x p)
453newSubscriberHold :: (HasSpiderTimeline x, Patch p) => Hold x p -> IO (Subscriber x p)
464newSubscriberHold h = return $ Subscriber
454newSubscriberHold h = return $ Subscriber
465 { subscriberPropagate = {-# SCC "traverseHold" #-} propagateSubscriberHold h
455 { subscriberPropagate = {-# SCC "traverseHold" #-} propagateSubscriberHold h
src/Reflex/TriggerEvent/Class.hs+6
@@ -12,6 +12,7 @@ import Reflex.Class
12import Control.Monad.Reader
12import Control.Monad.Reader
13import Control.Monad.State
13import Control.Monad.State
14import qualified Control.Monad.State.Strict as Strict
14import qualified Control.Monad.State.Strict as Strict
15+import Control.Monad.Trans.Maybe (MaybeT)
15
16
16--TODO: Shouldn't have IO hard-coded
17--TODO: Shouldn't have IO hard-coded
17-- | 'TriggerEvent' represents actions that can create 'Event's that can be
18-- | 'TriggerEvent' represents actions that can create 'Event's that can be
@@ -47,3 +48,8 @@ instance TriggerEvent t m => TriggerEvent t (Strict.StateT s m) where
47 newTriggerEvent = lift newTriggerEvent
48 newTriggerEvent = lift newTriggerEvent
48 newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
49 newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
49 newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
50 newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
51+
52+instance TriggerEvent t m => TriggerEvent t (MaybeT m) where
53+ newTriggerEvent = lift newTriggerEvent
54+ newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
55+ newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete