packages feed

reactive-banana 0.4.0.0 → 0.4.1.0

raw patch · 4 files changed

+60/−22 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Reactive.Banana.Implementation: instance MonadFix NetworkDescription
+ Reactive.Banana.Implementation: liftIOLater :: IO () -> NetworkDescription ()
+ Reactive.Banana.Incremental: instance FRP f => Apply (Discrete f) (Event f)
+ Reactive.Banana.Model: (<@) :: Apply f g => f a -> g b -> g a
+ Reactive.Banana.Model: (<@>) :: Apply f g => f (a -> b) -> g a -> g b
+ Reactive.Banana.Model: class (Functor f, Functor g) => Apply f g
+ Reactive.Banana.Model: instance FRP f => Apply (Behavior f) (Event f)

Files

reactive-banana.cabal view
@@ -1,5 +1,5 @@ Name:                reactive-banana-Version:             0.4.0.0+Version:             0.4.1.0 Synopsis:            Small but solid library for                      functional reactive programming (FRP). Description:         
src/Reactive/Banana/Implementation.hs view
@@ -15,7 +15,7 @@     -- * Building event networks with input/output     -- $build     NetworkDescription, compile,-    AddHandler, fromAddHandler, fromPoll, reactimate, liftIO,+    AddHandler, fromAddHandler, fromPoll, reactimate, liftIO, liftIOLater,          -- * Running event networks     EventNetwork, actuate, pause,@@ -27,19 +27,20 @@     module Data.Dynamic,     ) where -import Reactive.Banana.PushIO hiding (compile)-import qualified Reactive.Banana.PushIO as Implementation-import qualified Reactive.Banana.Model as Model- import Control.Applicative+import Control.Concurrent import Control.Monad.RWS  import Data.Dynamic-import Data.List (nub) import Data.IORef+import Data.List (nub) import qualified Data.Map as Map import Data.Unique +import Reactive.Banana.PushIO hiding (compile)+import qualified Reactive.Banana.PushIO as Implementation+import qualified Reactive.Banana.Model as Model+ -- debug = putStrLn  {-----------------------------------------------------------------------------@@ -62,12 +63,15 @@     let paths1 = groupChannelsBy (\p q x -> p x >> q x) paths      -- prepare threading the cache as state-    rcache <- newIORef emptyCache-    writeIORef rcache cache+    rcache <- newEmptyMVar+    putMVar rcache cache     let run m = do-            cache <- readIORef rcache+            -- takeMVar  makes sure that network runs are sequential+            -- In particular, the network will deadlock+            -- if you try to call an event handler during a  reactimate .+            cache <- takeMVar rcache             (_,cache') <- runRun m cache-            writeIORef rcache cache'+            putMVar rcache cache'         paths2 = map (\(i,p) -> (i, run . p)) $ paths1          return paths2@@ -142,7 +146,7 @@ -}  type AddHandler'  = (Channel, AddHandler Universe)-type Preparations = ([Model.Event Flavor (IO ())], [AddHandler'])+type Preparations = ([Model.Event Flavor (IO ())], [AddHandler'], [IO ()])  -- | Monad for describing event networks. -- @@ -166,11 +170,13 @@ instance Applicative (NetworkDescription) where     pure    = Prepare . pure     f <*> a = Prepare $ unPrepare f <*> unPrepare a+instance MonadFix (NetworkDescription) where+    mfix f  = Prepare $ mfix (unPrepare . f)  -- | Output. -- Execute the 'IO' action whenever the event occurs. reactimate :: Model.Event PushIO (IO ()) -> NetworkDescription ()-reactimate e = Prepare $ tell ([e], [])+reactimate e = Prepare $ tell ([e], [], [])  -- | A value of type @AddHandler a@ is just a facility for registering -- callback functions, also known as event handlers.@@ -193,7 +199,7 @@ fromAddHandler addHandler = Prepare $ do         channel <- newChannel         let addHandler' k = addHandler $ k . toUniverse channel-        tell ([], [(channel, addHandler')])+        tell ([], [(channel, addHandler')], [])         return $ input channel     where     newChannel = do c <- get; put $! c+1; return c@@ -213,18 +219,26 @@ fromPoll :: IO a -> NetworkDescription (Model.Behavior PushIO a) fromPoll m = return $ poll m +-- | Lift an 'IO' action into the 'NetworkDescription' monad,+-- but defer its execution until compilation time.+-- This can be useful for recursive definitions using 'MonadFix'.+liftIOLater :: IO () -> NetworkDescription ()+liftIOLater m = Prepare $ tell ([],[], [m])+ -- | Compile a 'NetworkDescription' into an 'EventNetwork' -- that you can 'actuate', 'pause' and so on. compile :: NetworkDescription () -> IO EventNetwork compile (Prepare m) = do-    (_,_,(outputs,inputs)) <- runRWST m () 0+    (_,_,(outputs,inputs,liftIOs)) <- runRWST m () 0+    sequence_ liftIOs          let -- union of all  reactimates         graph = mconcat outputs :: Model.Event Flavor (IO ())     paths <- compileHandlers graph          let -- register event handlers-        register = fmap sequence_ . sequence . map snd . applyChannels inputs $ paths+        register = fmap sequence_ . sequence . map snd . applyChannels inputs+                 $ paths     makeEventNetwork register  -- FIXME: make this faster
src/Reactive/Banana/Incremental.hs view
@@ -3,6 +3,7 @@          Derived data type, a hybrid between  Event  and  Behavior ------------------------------------------------------------------------------}+{-# LANGUAGE MultiParamTypeClasses #-} module Reactive.Banana.Incremental (     -- * Why a third type Discrete?     -- $discrete@@ -36,7 +37,8 @@ there are many different ways of implementing /incremental computations/. But I don't know a unified theory for them, so-I have decided that the reactive-banana will give /explicit control over updates to the user/+I have decided that the reactive-banana will give+/explicit control over updates to the user/ in the form of specialized data types like 'Discrete', and shall not attempt to bake experimental optimizations into the 'Behavior' type. @@ -44,12 +46,15 @@  * You get explicit control over updates (the 'changes' function), -* but you need to learn a third data type 'Discrete', which almost duplicates the 'Behavior' type.+* but you need to learn a third data type 'Discrete',+which almost duplicates the 'Behavior' type.  * Even though the type 'Behavior' is more fundamental, you will probably use 'Discrete' more often. -That said, 'Discrete' is not a new primitive type, but built from exising types and combinators; you are encouraged to look at the source code.+That said, 'Discrete' is not a new primitive type,+but built from exising types and combinators;+you are encouraged to look at the source code.  If you are an FRP implementor, I encourage you to find a better solution. But if you are a user, you may want to accept the trade-off for now.@@ -90,6 +95,10 @@ applyD :: FRP f => Discrete f (a -> b) -> Event f a -> Event f b applyD = apply . value +-- | Overloading 'applyD'+instance FRP f => Apply (Discrete f) (Event f) where+    (<@>) = applyD+ -- | Functor instance instance FRP f => Functor (Discrete f) where     fmap f r = stepperD (f $ initial r) $ fmap f (changes r)@@ -107,4 +116,3 @@         left  f (_,x) = (f,x)         right x (f,_) = (f,x) -    
src/Reactive/Banana/Model.hs view
@@ -3,7 +3,8 @@          Class interface + Semantic model ------------------------------------------------------------------------------}-{-# LANGUAGE TypeFamilies, FlexibleContexts, FlexibleInstances, EmptyDataDecls #-}+{-# LANGUAGE TypeFamilies, FlexibleContexts, FlexibleInstances, EmptyDataDecls,+  MultiParamTypeClasses #-} module Reactive.Banana.Model (     -- * Synopsis     -- | Combinators for building event networks and their semantics.@@ -14,7 +15,7 @@     Event, Behavior,     -- $classes     -- * Derived Combinators-    whenE, mapAccum,+    whenE, mapAccum, Apply(..),          -- * Model implementation     Model,@@ -182,6 +183,21 @@ mapAccum :: FRP f => acc -> Event f (acc -> (x,acc)) -> (Event f x, Behavior f acc) mapAccum acc ef = (fst <$> e, stepper acc (snd <$> e))     where e = accumE (undefined,acc) ((. snd) <$> ef)+++infixl 4 <@>, <@++-- | Class for overloading the 'apply' function.+class (Functor f, Functor g) => Apply f g where+    -- | Infix operation for the 'apply' function, similar to '<*>'+    (<@>) :: f (a -> b) -> g a -> g b+    -- | Convenience function, similar to '<*'+    (<@)  :: f a -> g b -> g a+    +    f <@ g = (const <$> f) <@> g ++instance FRP f => Apply (Behavior f) (Event f) where+    (<@>) = apply  {-----------------------------------------------------------------------------     Semantic model