netwire 1.1.0 → 1.2.0
raw patch · 13 files changed
+407/−308 lines, 13 files
Files
- FRP/NetWire.hs +10/−1
- FRP/NetWire/Analyze.hs +23/−9
- FRP/NetWire/Calculus.hs +18/−7
- FRP/NetWire/Concurrent.hs +3/−3
- FRP/NetWire/Event.hs +78/−144
- FRP/NetWire/IO.hs +5/−23
- FRP/NetWire/Random.hs +17/−3
- FRP/NetWire/Request.hs +2/−0
- FRP/NetWire/Session.hs +61/−27
- FRP/NetWire/Switch.hs +8/−8
- FRP/NetWire/Tools.hs +111/−31
- FRP/NetWire/Wire.hs +63/−45
- netwire.cabal +8/−7
FRP/NetWire.hs view
@@ -10,7 +10,7 @@ module FRP.NetWire ( -- * Wires- Wire, Event, Output, Time,+ Wire, Output, Time, -- * Reactive sessions Session,@@ -24,6 +24,11 @@ stepSF, stepWirePure, + -- * Inhibition+ InhibitException(..),+ inhibitEx,+ noEvent,+ -- * Netwire Reexports module FRP.NetWire.Analyze, module FRP.NetWire.Calculus,@@ -36,10 +41,14 @@ module FRP.NetWire.Tools, -- * Other convenience reexports+ module Control.Monad.IO.Class,+ module Control.Monad.IO.Control, module Data.Functor.Identity ) where +import Control.Monad.IO.Class+import Control.Monad.IO.Control import Data.Functor.Identity import FRP.NetWire.Analyze import FRP.NetWire.Calculus
FRP/NetWire/Analyze.hs view
@@ -36,6 +36,8 @@ -- -- If you need an average over all samples ever produced, consider using -- 'avgAll' instead.+--+-- Never inhibits. Feedback by delay. avg :: forall m v. (Fractional v, Monad m, NFData v, U.Unbox v) => Int -> Wire m v v avg n = mkGen $ \_ x -> return (Right x, avg' (U.replicate n (x/d)) x 0)@@ -46,12 +48,12 @@ let cur = let cur = succ cur' in if cur >= n then 0 else cur x' = samples' U.! cur samples =- x' `seq` runST $ do+ x' `deepseq` runST $ do s <- U.unsafeThaw samples' UM.write s cur x U.unsafeFreeze s let s = s' - x' + x- s `deepseq` return (Right s, avg' samples s cur)+ s' `deepseq` cur `seq` return (Right s, avg' samples s cur) d :: v d = realToFrac n@@ -62,6 +64,8 @@ -- Please note that somewhat surprisingly this wire runs in constant -- space and is generally faster than 'avg', but most applications will -- benefit from averages over only the last few samples.+--+-- Never inhibits. Feedback by delay. avgAll :: forall m v. (Fractional v, Monad m, NFData v) => Wire m v v avgAll = mkGen $ \_ x -> return (Right x, avgAll' 1 x)@@ -71,7 +75,7 @@ mkGen $ \_ x -> let n = n' + 1 a = a' - a'/n + x/n in- n `deepseq` a `deepseq` return (Right a, avgAll' n a)+ n `deepseq` a' `deepseq` return (Right a, avgAll' n a) -- | Calculate the average number of frames per virtual second for the@@ -81,6 +85,8 @@ -- using the stepping functions in "FRP.NetWire.Session". If this clock -- doesn't represent real time, then the output of this wire won't -- either.+--+-- Never inhibits. avgFps :: forall a m. Monad m => Int -> Wire m a Double avgFps = avgFps' . avg@@ -95,35 +101,43 @@ -- | Emits an event, whenever the input signal changes. The event -- contains the last input value and the time elapsed since the last -- change.+--+-- Inhibits on no change. -diff :: forall a m. (Eq a, Monad m) => Wire m a (Event (a, Time))+diff :: forall a m. (Eq a, Monad m) => Wire m a (a, Time) diff = mkGen $ \(wsDTime -> dt) x' ->- return (Right Nothing, diff' dt x')+ return (Left noEvent, diff' dt x') where- diff' :: Time -> a -> Wire m a (Event (a, Time))+ diff' :: Time -> a -> Wire m a (a, Time) diff' t' x' = mkGen $ \(wsDTime -> dt) x -> let t = t' + dt in if x' == x- then return (Right Nothing, diff' t x')- else return (Right (Just (x', t)), diff' 0 x)+ then return (Left noEvent, diff' t x')+ else return (Right (x', t), diff' 0 x) -- | Return the high peak.+--+-- Never inhibits. Feedback by delay. highPeak :: (Monad m, NFData a, Ord a) => Wire m a a highPeak = peakBy compare -- | Return the low peak.+--+-- Never inhibits. Feedback by delay. lowPeak :: (Monad m, NFData a, Ord a) => Wire m a a lowPeak = peakBy (flip compare) -- | Return the high peak with the given comparison function.+--+-- Never inhibits. Feedback by delay. peakBy :: forall a m. (Monad m, NFData a) => (a -> a -> Ordering) -> Wire m a a peakBy comp = mkGen $ \_ x -> return (Right x, peakBy' x)@@ -132,4 +146,4 @@ peakBy' p' = mkGen $ \_ x -> do let p = if comp x p' == GT then x else p'- p `deepseq` return (Right p, peakBy' p)+ p' `deepseq` return (Right p, peakBy' p)
FRP/NetWire/Calculus.hs view
@@ -19,7 +19,9 @@ import FRP.NetWire.Wire --- | Differentiate over time. Inhibits at first instant.+-- | Differentiate over time.+--+-- Inhibits at first instant. derivative :: (Monad m, NFData v, VectorSpace v, Scalar v ~ Double) => Wire m v v derivative =@@ -30,19 +32,28 @@ -- | Differentiate over time. The argument is the value before the -- first instant.+--+-- Never inhibits. Direct feedback. -derivativeFrom :: (Monad m, NFData v, VectorSpace v, Scalar v ~ Double) => v -> Wire m v v-derivativeFrom y1 =- mkGen $ \(wsDTime -> dt) y2 -> do- let dy = (y2 ^-^ y1) ^/ dt- dy `deepseq` return (Right dy, derivativeFrom y2)+derivativeFrom ::+ forall m v. (Monad m, NFData v, VectorSpace v, Scalar v ~ Double) =>+ v -> Wire m v v+derivativeFrom y1 = derivativeFrom' zeroV y1+ where+ derivativeFrom' :: v -> v -> Wire m v v+ derivativeFrom' dy' y1 =+ mkGen $ \(wsDTime -> dt) y2 -> do+ let dy = (y2 ^-^ y1) ^/ dt+ dy' `deepseq` return (Right dy', derivativeFrom' dy y2) -- | Integrate over time. The argument is the integration constant.+--+-- Never inhibits. Direct feedback. integral :: (Monad m, NFData v, VectorSpace v, Scalar v ~ Double) => v -> Wire m v v integral x1 = mkGen $ \ws dx -> do let dt = wsDTime ws x2 = x1 ^+^ dt *^ dx- x2 `deepseq` return (Right x2, integral x2)+ x1 `deepseq` return (Right x1, integral x2)
FRP/NetWire/Concurrent.hs view
@@ -25,7 +25,7 @@ import FRP.NetWire.Wire --- | Concurrent version of '(***)'. Passes its input signals to both+-- | Concurrent version of '***'. Passes its input signals to both -- argument wires concurrently. (~*~) :: Wire IO a c -> Wire IO b d -> Wire IO (a, b) (c, d)@@ -41,7 +41,7 @@ infixr 3 ~*~ --- | Concurrent version of '(&&&)'. Passes its input signal to both+-- | Concurrent version of '&&&'. Passes its input signal to both -- argument wires concurrently. (~&~) :: Wire IO a b -> Wire IO a c -> Wire IO a (b, c)@@ -50,7 +50,7 @@ infixr 3 ~&~ --- | Concurrent version of '(<+>)'. Passes its input signal to both+-- | Concurrent version of '<+>'. Passes its input signal to both -- argument wires concurrently, returning the result of the first wire -- which does not inhibit.
FRP/NetWire/Event.hs view
@@ -4,7 +4,8 @@ -- License: BSD3 -- Maintainer: Ertugrul Soeylemez <es@ertes.de> ----- Events.+-- Events. None of these wires supports feedback, because they all can+-- inhibit. module FRP.NetWire.Event ( -- * Producing events@@ -14,14 +15,10 @@ edgeBy, edgeJust, never,- now, once, repeatedly, repeatedlyList, - -- * Wire transformers- wait,- -- * Event transformers -- ** Delaying events dam,@@ -33,10 +30,8 @@ notYet, takeEvents, takeFor,- -- ** Manipulating events- accum,- -- ** Mapping to continuous signals- hold, dHold+ -- ** Tools+ event ) where @@ -49,32 +44,16 @@ import FRP.NetWire.Wire --- | This function corresponds to the 'iterate' function for lists.--- Begins with an initial output value, which is not emitted. Each time--- an input event is received, its function is applied to the current--- accumulator and the new value is emitted.--accum :: forall a m. Monad m => a -> Wire m (Event (a -> a)) (Event a)-accum ee' = accum'- where- accum' :: Wire m (Event (a -> a)) (Event a)- accum' =- mkGen $ \_ ->- return .- maybe (Right Nothing, accum')- (\f -> let ee = f ee' in ee `seq` (Right (Just ee), accum ee))----- | Produce an event once after the specified delay and never again.+-- | Produce a signal once after the specified delay and never again. -- The event's value will be the input signal at that point. -after :: Monad m => Time -> Wire m a (Event a)+after :: Monad m => Time -> Wire m a a after t' = mkGen $ \(wsDTime -> dt) x -> let t = t' - dt in if t <= 0- then return (Right (Just x), never)- else return (Right Nothing, after t)+ then return (Right x, never)+ else return (Left noEvent, after t) -- | Produce an event according to the given list of time deltas and@@ -83,18 +62,18 @@ -- produces the event @'a'@ after one second, @'b'@ after three seconds -- and @'c'@ after six seconds. -afterEach :: forall a b m. Monad m => [(Time, b)] -> Wire m a (Event b)+afterEach :: forall a b m. Monad m => [(Time, b)] -> Wire m a b afterEach = afterEach' 0 where- afterEach' :: Time -> [(Time, b)] -> Wire m a (Event b)+ afterEach' :: Time -> [(Time, b)] -> Wire m a b afterEach' _ [] = never afterEach' t' d@((int, x):ds) = mkGen $ \(wsDTime -> dt) _ -> let t = t' + dt in if t >= int then let nextT = t - int- in nextT `seq` return (Right (Just x), afterEach' (t - int) ds)- else return (Right Nothing, afterEach' t d)+ in nextT `seq` return (Right x, afterEach' (t - int) ds)+ else return (Left noEvent, afterEach' t d) -- | Event dam. Collects all values from the input list and emits one@@ -103,15 +82,15 @@ -- Note that this combinator can cause event congestion. If you feed -- values faster than it can produce, it will leak memory. -dam :: forall a m. Monad m => Wire m [a] (Event a)+dam :: forall a m. Monad m => Wire m [a] a dam = dam' [] where- dam' :: [a] -> Wire m [a] (Event a)+ dam' :: [a] -> Wire m [a] a dam' xs = mkGen $ \_ ys -> case xs ++ ys of- [] -> return (Right Nothing, dam' [])- (ee:rest) -> return (Right (Just ee), dam' rest)+ [] -> return (Left noEvent, dam' [])+ (x:rest) -> return (Right x, dam' rest) -- | Delay events by the time interval in the left signal.@@ -122,19 +101,19 @@ -- starts to drop), it will leak memory. Use 'delayEventSafe' to -- prevent this. -delayEvents :: forall a m. Monad m => Wire m (Time, Event a) (Event a)+delayEvents :: forall a m. Monad m => Wire m (Time, Maybe a) a delayEvents = delayEvent' Seq.empty 0 where- delayEvent' :: Seq (Time, a) -> Time -> Wire m (Time, Event a) (Event a)+ delayEvent' :: Seq (Time, a) -> Time -> Wire m (Time, Maybe a) a delayEvent' es' t' = mkGen $ \(wsDTime -> dt) (int, ev) -> do let t = t' + dt es = t `seq` maybe es' (\ee -> es' |> (t + int, ee)) ev case Seq.viewl es of- Seq.EmptyL -> return (Right Nothing, delayEvent' es 0)+ Seq.EmptyL -> return (Left noEvent, delayEvent' es 0) (et, ee) :< rest- | t >= et -> return (Right (Just ee), delayEvent' rest t)- | otherwise -> return (Right Nothing, delayEvent' es t)+ | t >= et -> return (Right ee, delayEvent' rest t)+ | otherwise -> return (Left noEvent, delayEvent' es t) -- | Delay events by the time interval in the left signal. The event@@ -146,66 +125,49 @@ -- However, if it's decreased below the number of currently queued -- events, the events are not deleted. -delayEventsSafe :: forall a m. Monad m => Wire m (Time, Int, Event a) (Event a)+delayEventsSafe :: forall a m. Monad m => Wire m (Time, Int, Maybe a) a delayEventsSafe = delayEventSafe' Seq.empty 0 where- delayEventSafe' :: Seq (Time, a) -> Time -> Wire m (Time, Int, Event a) (Event a)+ delayEventSafe' :: Seq (Time, a) -> Time -> Wire m (Time, Int, Maybe a) a delayEventSafe' es' t' = mkGen $ \(wsDTime -> dt) (int, maxEvs, ev') -> do let t = t' + dt ev = guard (Seq.length es' < maxEvs) >> ev' es = t `seq` maybe es' (\ee -> es' |> (t + int, ee)) ev case Seq.viewl es of- Seq.EmptyL -> return (Right Nothing, delayEventSafe' es 0)+ Seq.EmptyL -> return (Left noEvent, delayEventSafe' es 0) (et, ee) :< rest- | t >= et -> return (Right (Just ee), delayEventSafe' rest t)- | otherwise -> return (Right Nothing, delayEventSafe' es t)----- | Decoupled variant of 'hold'.--dHold :: forall a m. Monad m => a -> Wire m (Event a) a-dHold x0 = dHold'- where- dHold' :: Wire m (Event a) a- dHold' =- mkGen $ \_ ->- return . maybe (Right x0, dHold') (\x1 -> (Right x0, dHold x1))+ | t >= et -> return (Right ee, delayEventSafe' rest t)+ | otherwise -> return (Left noEvent, delayEventSafe' es t) -- | Drop the given number of events, before passing events through. -dropEvents :: forall a m. Monad m => Int -> Wire m (Event a) (Event a)+dropEvents :: forall a m. Monad m => Int -> Wire m a a dropEvents 0 = identity-dropEvents n = drop'- where- drop' :: Wire m (Event a) (Event a)- drop' =- mkGen $ \_ ->- return .- maybe (Right Nothing, drop')- (const (Right Nothing, dropEvents (pred n)))+dropEvents n =+ mkGen $ \_ x -> return (Right x, dropEvents (pred n)) -- | Timed event gate for the right signal, which begins closed and -- opens after the time interval in the left signal has passed. -dropFor :: forall a m. Monad m => Wire m (Time, Event a) (Event a)+dropFor :: forall a m. Monad m => Wire m (Time, a) a dropFor = dropFor' 0 where- dropFor' :: Time -> Wire m (Time, Event a) (Event a)+ dropFor' :: Time -> Wire m (Time, a) a dropFor' t' =- mkGen $ \(wsDTime -> dt) (int, ev) ->+ mkGen $ \(wsDTime -> dt) (int, x) -> let t = t' + dt in if t >= int- then return (Right ev, arr snd)- else return (Right Nothing, dropFor' t)+ then return (Right x, arr snd)+ else return (Left noEvent, dropFor' t) -- | Produce a single event with the right signal whenever the left -- signal switches from 'False' to 'True'. -edge :: Monad m => Wire m (Bool, a) (Event a)+edge :: Monad m => Wire m (Bool, a) a edge = edgeBy fst snd @@ -213,141 +175,113 @@ -- to 'True' for the input signal, produce an event carrying the value -- given by applying the second argument function to the input signal. -edgeBy :: forall a b m. Monad m => (a -> Bool) -> (a -> b) -> Wire m a (Event b)+edgeBy :: forall a b m. Monad m => (a -> Bool) -> (a -> b) -> Wire m a b edgeBy p f = edgeBy' where- edgeBy' :: Wire m a (Event b)+ edgeBy' :: Wire m a b edgeBy' = mkGen $ \_ subject -> if p subject- then return (Right (Just (f subject)), switchBack)- else return (Right Nothing, edgeBy')+ then return (Right (f subject), switchBack)+ else return (Left noEvent, edgeBy') - switchBack :: Wire m a (Event b)+ switchBack :: Wire m a b switchBack = mkGen $ \_ subject ->- return (Right Nothing, if p subject then switchBack else edgeBy')+ return (Left noEvent, if p subject then switchBack else edgeBy') -- | Produce a single event carrying the value of the input signal, -- whenever the input signal switches to 'Just'. -edgeJust :: Monad m => Wire m (Maybe a) (Event a)+edgeJust :: Monad m => Wire m (Maybe a) a edgeJust = edgeBy isJust fromJust --- | Turn discrete events into continuous signals. Initially produces--- the argument value. Each time an event occurs, the produced value is--- switched to the event's value.+-- | Variant of 'exhibit', which produces a 'Maybe' instead of an+-- 'Either'.+--+-- Never inhibits. Same feedback properties as argument wire. -hold :: forall a m. Monad m => a -> Wire m (Event a) a-hold x0 = hold'- where- hold' :: Wire m (Event a) a- hold' =- mkGen $ \_ ->- return .- maybe (Right x0, hold')- (Right &&& hold)+event :: Monad m => Wire m a b -> Wire m a (Maybe b)+event w' =+ mkGen $ \ws x' -> do+ (mx, w) <- toGen w' ws x'+ case mx of+ Left _ -> return (Right Nothing, event w)+ Right x -> return (Right (Just x), event w) --- | Never produce an event.+-- | Never produce an event. This is equivalent to 'inhibit', but with+-- a contextually more appropriate exception message. -never :: Monad m => Wire m a (Event b)-never = constant Nothing+never :: Monad m => Wire m a b+never = mkGen $ \_ _ -> return (Left noEvent, never) -- | Suppress the first event occurence. -notYet :: Monad m => Wire m (Event a) (Event a)-notYet = mkGen $ \_ -> return . maybe (Right Nothing, notYet) (const (Right Nothing, identity))+notYet :: Monad m => Wire m a a+notYet = mkGen $ \_ _ -> return (Left noEvent, identity) -- | Produce an event at the first instant and never again. -now :: Monad m => b -> Wire m a (Event b)-now x = constantAfter Nothing (Just x)----- | Pass the first event occurence through and suppress all future--- events.--once :: Monad m => Wire m (Event a) (Event a)-once =- mkGen $ \_ ev ->- case ev of- Nothing -> return (Right Nothing, once)- Just _ -> return (Right ev, constant Nothing)+once :: Monad m => Wire m a a+once = mkGen $ \_ x -> return (Right x, never) -- | Emit the right signal event each time the left signal interval -- passes. -repeatedly :: forall a m. Monad m => Wire m (Time, a) (Event a)+repeatedly :: forall a m. Monad m => Wire m (Time, a) a repeatedly = repeatedly' 0 where- repeatedly' :: Time -> Wire m (Time, a) (Event a)+ repeatedly' :: Time -> Wire m (Time, a) a repeatedly' t' = mkGen $ \(wsDTime -> dt) (int, x) -> let t = t' + dt in if t >= int then let nextT = fmod t int- in nextT `seq` return (Right (Just x), repeatedly' nextT)- else return (Right Nothing, repeatedly' t)+ in nextT `seq` return (Right x, repeatedly' nextT)+ else return (Left noEvent, repeatedly' t) -- | Each time the signal interval passes emit the next element from the -- given list. -repeatedlyList :: forall a m. Monad m => [a] -> Wire m Time (Event a)+repeatedlyList :: forall a m. Monad m => [a] -> Wire m Time a repeatedlyList = repeatedly' 0 where- repeatedly' :: Time -> [a] -> Wire m Time (Event a)- repeatedly' _ [] = constant Nothing+ repeatedly' :: Time -> [a] -> Wire m Time a+ repeatedly' _ [] = never repeatedly' t' x@(x0:xs) = mkGen $ \(wsDTime -> dt) int -> let t = t' + dt in if t >= int then let nextT = fmod t int- in nextT `seq` return (Right (Just x0), repeatedly' nextT xs)- else return (Right Nothing, repeatedly' t x)+ in nextT `seq` return (Right x0, repeatedly' nextT xs)+ else return (Left noEvent, repeatedly' t x) -- | Pass only the first given number of events. Then suppress events -- forever. -takeEvents :: forall a m. Monad m => Int -> Wire m (Event a) (Event a)-takeEvents 0 = constant Nothing-takeEvents n = take'- where- take' :: Wire m (Event a) (Event a)- take' =- mkGen $ \_ ev ->- case ev of- Nothing -> return (Right Nothing, take')- Just _ -> return (Right ev, takeEvents (pred n))+takeEvents :: forall a m. Monad m => Int -> Wire m a a+takeEvents 0 = never+takeEvents n = mkGen $ \_ x -> return (Right x, takeEvents (pred n)) -- | Timed event gate for the right signal, which starts open and slams -- shut after the left signal time interval passed. -takeFor :: forall a m. Monad m => Wire m (Time, Event a) (Event a)+takeFor :: forall a m. Monad m => Wire m (Time, a) a takeFor = takeFor' 0 where- takeFor' :: Time -> Wire m (Time, Event a) (Event a)+ takeFor' :: Time -> Wire m (Time, a) a takeFor' t' =- mkGen $ \(wsDTime -> dt) (int, ev) ->+ mkGen $ \(wsDTime -> dt) (int, x) -> let t = t' + dt in if t >= int- then return (Right Nothing, constant Nothing)- else return (Right ev, takeFor' t)----- | Inhibit the signal, unless an event occurs.--wait :: Monad m => Wire m (Event a) a-wait =- mkGen $ \_ ev ->- case ev of- Nothing -> return (Left (inhibitEx "Waiting for event"), wait)- Just ee -> return (Right ee, wait)+ then return (Left noEvent, never)+ else return (Right x, takeFor' t)
FRP/NetWire/IO.hs view
@@ -9,7 +9,6 @@ module FRP.NetWire.IO ( -- * IO Actions execute,- executeEvery, executeOnce ) where@@ -25,34 +24,17 @@ -- -- Note: If the action throws an exception, then this wire inhibits the -- signal.+--+-- Inhibits on exception. No feedback. execute :: MonadControlIO m => Wire m (m a) a-execute =- mkGen $ \_ c -> liftM (, execute) (try c)----- | Executes the IO action in the right input signal periodically--- keeping its most recent result value.--executeEvery :: forall a m. MonadControlIO m => Wire m (Time, m a) a-executeEvery = executeEvery' True 0 (Left (inhibitEx "No result yet."))- where- executeEvery' :: Bool -> Time -> Output a -> Wire m (Time, m a) a- executeEvery' firstRun t' mx' =- mkGen $ \(wsDTime -> dt) (int, c) ->- let t = t' + dt in- if t >= int || firstRun- then do- let nextT = fmod t int- mx <- nextT `seq` try c- case mx of- Left _ -> return (mx', executeEvery' False nextT mx')- Right _ -> return (mx, executeEvery' False nextT mx)- else return (mx', executeEvery' False t mx')+execute = mkGen $ \_ c -> liftM (, execute) (try c) -- | Executes the IO action in the input signal and inhibits, until it -- succeeds without an exception. Keeps the result forever.+--+-- Inhibits until the first result value. No feedback. executeOnce :: MonadControlIO m => Wire m (m a) a executeOnce =
FRP/NetWire/Random.hs view
@@ -28,12 +28,16 @@ -- | Impure noise between 0 (inclusive) and 1 (exclusive).+--+-- Never inhibits. noise :: MonadIO m => Wire m a Double noise = noiseGen -- | Impure noise between -1 (inclusive) and 1 (exclusive).+--+-- Never inhibits. noise1 :: MonadIO m => Wire m a Double noise1 =@@ -43,6 +47,8 @@ -- | Impure noise.+--+-- Never inhibits. noiseGen :: (MonadIO m, MTRandom b) => Wire m a b noiseGen =@@ -52,19 +58,23 @@ -- | Impure noise between 0 (inclusive) and the input signal--- (exclusive). Note: The noise is generated by multiplying a+-- (exclusive). Note: The noise is generated by multiplying with a -- 'Double', hence the precision is limited.+--+-- Never inhibits. Feedback by delay. noiseR :: (MonadIO m, Real a, Integral b) => Wire m a b noiseR = mkGen $ \(wsRndGen -> mt) n -> do x' <- liftIO (random mt) let x = floor ((x' :: Double) * realToFrac n)- x `seq` return (Right x, noiseR)+ return (Right x, noiseR) -- | Pure noise. For impure wires it's recommended to use the impure -- noise generators.+--+-- Never inhibits. pureNoise :: (Monad m, R.RandomGen g, R.Random b) => g -> Wire m a b pureNoise g' =@@ -75,15 +85,19 @@ -- | Pure noise in a range. For impure wires it's recommended to use -- the impure noise generators.+--+-- Never inhibits. Feedback by delay. pureNoiseR :: (Monad m, R.RandomGen g, R.Random b) => g -> Wire m (b, b) b pureNoiseR g' = mkGen $ \_ range -> let (x, g) = R.randomR range g'- in x `seq` return (Right x, pureNoise g)+ in return (Right x, pureNoise g) -- | Impure random boolean.+--+-- Never inhibits. wackelkontakt :: MonadIO m => Wire m a Bool wackelkontakt = noiseGen
FRP/NetWire/Request.hs view
@@ -18,6 +18,8 @@ -- | Choose a unique identifier when switching in and keep it.+--+-- Never inhibits. identifier :: MonadIO m => Wire m a Int identifier =
FRP/NetWire/Session.hs view
@@ -19,40 +19,53 @@ import Control.Applicative import Control.Concurrent.STM-import Control.Exception+import Control.Exception.Control+import Control.Monad.IO.Class+import Control.Monad.IO.Control import Data.IORef import Data.Time.Clock import FRP.NetWire.Wire --- | Reactive sessions with the given time type.+-- | Reactive sessions with the given input and output types over the+-- given monad. The monad must have a 'MonadControlIO' instance to be+-- usable with the stepping functions. -data Session a b =+data Session m a b = Session {- sessFreeVar :: TVar Bool, -- ^ False, if in use.- sessStateRef :: IORef (WireState IO), -- ^ State of the last instant.- sessTimeRef :: IORef UTCTime, -- ^ Time of the last instant.- sessWireRef :: IORef (Wire IO a b) -- ^ Wire for the next instant.+ sessFreeVar :: TVar Bool, -- ^ False, if in use.+ sessStateRef :: IORef (WireState m), -- ^ State of the last instant.+ sessTimeRef :: IORef UTCTime, -- ^ Time of the last instant.+ sessWireRef :: IORef (Wire m a b) -- ^ Wire for the next instant. } -- | Feed the given input value into the reactive system performing the -- next instant using real time. -stepWire :: a -> Session a b -> IO (Output b)+stepWire ::+ MonadControlIO m+ => a -- ^ Input value.+ -> Session m a b -- ^ Session to step.+ -> m (Output b) -- ^ System's output. stepWire x' sess = withBlock sess $ do- t <- getCurrentTime+ t <- liftIO getCurrentTime stepWireTime' t x' sess -- | Feed the given input value into the reactive system performing the -- next instant using the given time delta. -stepWireDelta :: NominalDiffTime -> a -> Session a b -> IO (Output b)+stepWireDelta ::+ MonadControlIO m+ => NominalDiffTime -- ^ Time delta.+ -> a -- ^ Input value.+ -> Session m a b -- ^ Session to step.+ -> m (Output b) -- ^ System's output. stepWireDelta dt x' sess = withBlock sess $ do- t' <- readIORef (sessTimeRef sess)+ t' <- liftIO (readIORef $ sessTimeRef sess) let t@(UTCTime td tt) = addUTCTime dt t' td `seq` tt `seq` t `seq` stepWireTime' t x' sess @@ -61,55 +74,76 @@ -- next instant, which is at the given time. This function is -- thread-safe. -stepWireTime :: UTCTime -> a -> Session a b -> IO (Output b)+stepWireTime ::+ MonadControlIO m+ => UTCTime -- ^ Absolute time of the instant to perform.+ -> a -- ^ Input value.+ -> Session m a b -- ^ Session to step.+ -> m (Output b) -- ^ System's output. stepWireTime t' x' sess = withBlock sess (stepWireTime' t' x' sess) -- | Feed the given input value into the reactive system performing the--- next instant, which is at the given time. This function is *not*+-- next instant, which is at the given time. This function is /not/ -- thread-safe. -stepWireTime' :: UTCTime -> a -> Session a b -> IO (Output b)+stepWireTime' ::+ MonadIO m+ => UTCTime -- ^ Absolute time of the instant to perform.+ -> a -- ^ Input value.+ -> Session m a b -- ^ Session to step.+ -> m (Output b) -- ^ System's output. stepWireTime' t x' sess = do let Session { sessTimeRef = tRef, sessStateRef = wsRef, sessWireRef = wRef } = sess -- Time delta.- t' <- readIORef tRef+ t' <- liftIO (readIORef tRef) let dt = realToFrac (diffUTCTime t t')- dt `seq` writeIORef tRef t+ dt `seq` liftIO (writeIORef tRef t) -- Wire state.- ws' <- readIORef wsRef+ ws' <- liftIO (readIORef wsRef) let ws = ws' { wsDTime = dt }- ws `seq` writeIORef wsRef ws+ ws `seq` liftIO (writeIORef wsRef ws) -- Wire.- w' <- readIORef wRef+ w' <- liftIO (readIORef wRef) (x, w) <- toGen w' ws x'- w `seq` writeIORef wRef w+ w `seq` liftIO (writeIORef wRef w) return x -- | Perform an interlocked step function. -withBlock :: Session a b -> IO c -> IO c+withBlock ::+ MonadControlIO m+ => Session m a b -- ^ The session to mark as locked for the+ -- duration of the given computation.+ -> m c -- ^ Computation to perform.+ -> m c -- ^ Result. withBlock (Session { sessFreeVar = freeVar }) c = do- atomically (readTVar freeVar >>= check >> writeTVar freeVar False)- c `finally` atomically (writeTVar freeVar True)+ liftIO (atomically $ readTVar freeVar >>= check >> writeTVar freeVar False)+ c `finally` liftIO (atomically $ writeTVar freeVar True) -- | Initialize a reactive session and pass it to the given -- continuation. -withWire :: Wire IO a b -> (Session a b -> IO c) -> IO c+withWire ::+ MonadControlIO m+ => Wire m a b -- ^ Initial wire of the session.+ -> (Session m a b -> m c) -- ^ Continuation, which receives the+ -- session data.+ -> m c -- ^ Continuation's result. withWire w k = do- t@(UTCTime td tt) <- getCurrentTime- ws <- initWireState+ t@(UTCTime td tt) <- liftIO getCurrentTime+ ws <- liftIO initWireState sess <- td `seq` tt `seq` t `seq` ws `seq`+ liftIO $ Session <$> newTVarIO True <*> newIORef ws@@ -118,4 +152,4 @@ seq sess (k sess) `finally`- (readIORef (sessStateRef sess) >>= cleanupWireState)+ (liftIO $ readIORef (sessStateRef sess) >>= cleanupWireState)
FRP/NetWire/Switch.hs view
@@ -35,7 +35,7 @@ (Applicative m, Monad m, Traversable f) => (forall w. a -> f w -> f (b, w)) -> f (Wire m b c) ->- Wire m (a, Event (f (Wire m b c) -> f (Wire m b c))) (f c)+ Wire m (a, Maybe (f (Wire m b c) -> f (Wire m b c))) (f c) drpSwitch route wires''' = WGen $ \ws (x'', ev) -> do let wires'' = route x'' wires'''@@ -51,7 +51,7 @@ drpSwitchB :: (Applicative m, Monad m, Traversable f) => f (Wire m a b) ->- Wire m (a, Event (f (Wire m a b) -> f (Wire m a b))) (f b)+ Wire m (a, Maybe (f (Wire m a b) -> f (Wire m a b))) (f b) drpSwitchB wires'' = WGen $ \ws (x', ev) -> do r <- T.sequenceA $ fmap (\w' -> toGen w' ws x') wires''@@ -63,7 +63,7 @@ -- | Decoupled variant of 'rSwitch'. -drSwitch :: Monad m => Wire m a b -> Wire m (a, Event (Wire m a b)) b+drSwitch :: Monad m => Wire m a b -> Wire m (a, Maybe (Wire m a b)) b drSwitch w1' = WGen $ \ws (x', swEv) -> do (mx, w1) <- toGen w1' ws x'@@ -73,7 +73,7 @@ -- | Decoupled variant of 'switch'. -dSwitch :: Monad m => Wire m a (b, Event c) -> (c -> Wire m a b) -> Wire m a b+dSwitch :: Monad m => Wire m a (b, Maybe c) -> (c -> Wire m a b) -> Wire m a b dSwitch w1' f = WGen $ \ws x' -> do (m, w1) <- toGen w1' ws x'@@ -124,7 +124,7 @@ (Applicative m, Monad m, Traversable f) => (forall w. a -> f w -> f (b, w)) -> f (Wire m b c) ->- Wire m (a, Event (f (Wire m b c) -> f (Wire m b c))) (f c)+ Wire m (a, Maybe (f (Wire m b c) -> f (Wire m b c))) (f c) rpSwitch route wires''' = WGen $ \ws (x'', ev) -> do let wires'' = maybe id id ev wires'''@@ -144,7 +144,7 @@ rpSwitchB :: (Applicative m, Monad m, Traversable f) =>- f (Wire m a b) -> Wire m (a, Event (f (Wire m a b) -> f (Wire m a b))) (f b)+ f (Wire m a b) -> Wire m (a, Maybe (f (Wire m a b) -> f (Wire m a b))) (f b) rpSwitchB wires'' = WGen $ \ws (x', ev) -> do let wires' = maybe id id ev wires''@@ -158,7 +158,7 @@ -- switch takes switching events and switches to the wires contained in -- the events. The first argument is the initial wire. -rSwitch :: Monad m => Wire m a b -> Wire m (a, Event (Wire m a b)) b+rSwitch :: Monad m => Wire m a b -> Wire m (a, Maybe (Wire m a b)) b rSwitch w1 = WGen $ \ws (x', swEv) -> do let w' = maybe w1 id swEv@@ -173,7 +173,7 @@ -- event at some point. When this event is produced, then the signal -- path switches to the wire produced by the second argument function. -switch :: Monad m => Wire m a (b, Event c) -> (c -> Wire m a b) -> Wire m a b+switch :: Monad m => Wire m a (b, Maybe c) -> (c -> Wire m a b) -> Wire m a b switch w1' f = WGen $ \ws x' -> do (m, w1) <- toGen w1' ws x'
FRP/NetWire/Tools.hs view
@@ -16,10 +16,14 @@ timeFrom, -- * Signal transformers+ accum,+ delay, discrete,+ hold, keep, -- * Inhibitors+ forbid, inhibit, require, @@ -33,11 +37,6 @@ (-=>), (>=-), - -- * Switches- -- ** Unconditional switches- constantAfter,- initially,- -- * Arrow tools mapA, @@ -56,17 +55,23 @@ -- | Override the output value at the first non-inhibited instant.+--+-- Same inhibition properties as argument wire. Same feedback+-- properties as argument wire. (-->) :: Monad m => b -> Wire m a b -> Wire m a b y --> w' = WGen $ \ws x -> do (mx, w) <- toGen w' ws x case mx of- e@(Left _) -> return (e, y --> w)- Right _ -> return (Right y, w)+ Left _ -> return (mx, y --> w)+ Right _ -> return (Right y, w) -- | Override the input value, until the wire starts producing.+--+-- Same inhibition properties as argument wire. Same feedback+-- properties as argument wire. (>--) :: Monad m => a -> Wire m a b -> Wire m a b x' >-- w' =@@ -77,41 +82,64 @@ -- | Apply a function to the wire's output at the first non-inhibited -- instant.+--+-- Same inhibition properties as argument wire. Same feedback+-- properties as argument wire. (-=>) :: Monad m => (b -> b) -> Wire m a b -> Wire m a b f -=> w' = WGen $ \ws x' -> do (mx, w) <- toGen w' ws x' case mx of- e@(Left _) -> return (e, f -=> w)- Right x -> return (Right (f x), w)+ Left _ -> return (mx, f -=> w)+ Right x -> return (Right (f x), w) -- | Apply a function to the wire's input, until the wire starts -- producing.+--+-- Same inhibition properties as argument wire. Same feedback+-- properties as argument wire. (>=-) :: Monad m => (a -> a) -> Wire m a b -> Wire m a b f >=- w' = WGen $ \ws x' -> do (mx, w) <- toGen w' ws (f x')- case mx of- e@(Left _) -> return (e, f >=- w)- Right _ -> return (mx, w)+ return (mx, either (const (f >=- w)) (const w) mx) +-- | This function corresponds to the 'iterate' function for lists.+-- Begins with an initial output value. Each time an input function is+-- received, it is applied to the current accumulator and the new value+-- is emitted.+--+-- Never inhibits. Direct feedback.++accum :: Monad m => a -> Wire m (a -> a) a+accum x = mkGen $ \_ f -> x `seq` return (Right x, accum (f x))++ -- | The constant wire. Please use this function instead of @arr (const -- c)@.+--+-- Never inhibits. constant :: b -> Wire m a b constant = WConst --- | Produce the value of the second argument at the first instant.--- Then produce the second value forever.+-- | One-instant delay. Delay the signal for an instant returning the+-- argument value at the first instant. This wire is mainly useful to+-- add feedback support to wires, which wouldn't support it by+-- themselves. For example, the 'FRP.NetWire.Analyze.avg' wire does not+-- support feedback by itself, but the following works:+--+-- > do rec x <- delay 1 <<< avg 1000 -< x+--+-- Never inhibits. Direct feedback. -constantAfter :: Monad m => b -> b -> Wire m a b-constantAfter x1 x0 =- mkGen $ \_ _ -> return (Right x0, constant x1)+delay :: Monad m => a -> Wire m a a+delay r = mkGen $ \_ x -> return (Right r, delay x) -- | Turn a continuous signal into a discrete one. This transformer@@ -119,6 +147,8 @@ -- -- The interval length is followed in real time. If it's zero, then -- this wire acts like @second id@.+--+-- Never inhibits. Feedback by delay. discrete :: forall a m. Monad m => Wire m (Time, a) a discrete =@@ -142,7 +172,9 @@ -- | This function corresponds to 'try' for exceptions, allowing you to--- observe inhibited signals.+-- observe inhibited signals. See also 'FRP.NetWire.Event.event'.+--+-- Never inhibits. Same feedback properties as argument wire. exhibit :: Monad m => Wire m a b -> Wire m a (Output b) exhibit w' =@@ -158,12 +190,26 @@ fmod n d = n - d * realToFrac (floor $ n/d) +-- | Inhibit, when the left signal is true.+--+-- Inhibits on true left signal. No feedback.++forbid :: Monad m => Wire m (Bool, a) a+forbid =+ mkGen $ \_ (b, x) ->+ return (if b then Left (inhibitEx "Forbidden condition met") else Right x,+ forbid)++ -- | Effectively prevent a wire from rewiring itself. This function -- will turn any stateful wire into a stateless wire, rendering most -- wires useless. -- -- Note: This function should not be used normally. Use it only, if -- you know exactly what you're doing.+--+-- Same inhibition properties as first instant of argument wire. Same+-- feedback properties as first instant of argument wire. freeze :: Monad m => Wire m a b -> Wire m a b freeze w =@@ -172,28 +218,49 @@ return (mx, w) +-- | Keep the latest output.+--+-- Inhibits until first signal from argument wire. Same feedback+-- properties as argument wire.++hold :: forall a b m. Monad m => Wire m a b -> Wire m a b+hold w' =+ mkGen $ \ws x' -> do+ (mx, w) <- toGen w' ws x'+ case mx of+ Right x -> return (mx, hold' x w)+ Left _ -> return (mx, hold w)++ where+ hold' :: b -> Wire m a b -> Wire m a b+ hold' x0 w' =+ mkGen $ \ws x' -> do+ (mx, w) <- toGen w' ws x'+ case mx of+ Left _ -> return (Right x0, hold' x0 w)+ Right x -> return (Right x, hold' x w)++ -- | Identity signal transformer. Outputs its input.+--+-- Never inhibits. Feedback by delay. identity :: Monad m => Wire m a a identity = id -- | Unconditional inhibition with the given inhibition exception.+--+-- Always inhibits. inhibit :: (Exception e, Monad m) => Wire m e b inhibit = WGen $ \_ ex -> return (Left (toException ex), inhibit) --- | Produce the argument value at the first instant. Then act as the--- identity signal transformer forever.--initially :: Monad m => a -> Wire m a a-initially x0 =- mkGen $ \_ _ -> return (Right x0, identity)-- -- | Keep the value in the first instant forever.+--+-- Never inhibits. Feedback by delay. keep :: Monad m => Wire m a a keep = mkGen $ \_ x -> return (Right x, constant x)@@ -209,7 +276,9 @@ (x0:xs) -> arr (uncurry (:)) <<< a *** mapA a -< (x0, xs) --- | Inhibit right signal, when the left signal is false.+-- | Inhibit, when the left signal is false.+--+-- Inhibits on false left signal. No feedback. require :: Monad m => Wire m (Bool, a) a require =@@ -220,10 +289,13 @@ -- | Sample the given wire at specific intervals. Use this instead of -- 'discrete', if you want to prevent the signal from passing through--- the wire all the time.+-- the wire all the time. Returns the most recent result. -- -- The left signal interval is allowed to become zero, at which point -- the signal is passed through the wire at every instant.+--+-- Inhibits until the first result from the argument wire. Same+-- feedback properties as argument wire. sample :: forall a b m. Monad m => Wire m a b -> Wire m (Time, a) b sample w' =@@ -238,14 +310,18 @@ let t = t' + dt in if t >= int || int <= 0 then do- (mx, w) <- toGen w' ws x''- let nextT = fmod t int- nextT `seq` return (either (const mx') (const mx) mx, sample' nextT mx' w)+ (mmx, w) <- toGen w' (ws { wsDTime = t }) x''+ let mx = either (const mx') (const mmx) mmx+ nextT = fmod t int+ () `seq` return (mx, sample' nextT mx w) else return (mx', sample' t mx' w') -- | Wait for the first signal from the given wire and keep it forever.+--+-- Inhibits until signal from argument wire. Direct feedback, if+-- argument wire never inhibits, otherwise no feedback. swallow :: Monad m => Wire m a b -> Wire m a b swallow w' =@@ -261,12 +337,16 @@ -- | Get the local time.+--+-- Never inhibits. time :: Monad m => Wire m a Time time = timeFrom 0 -- | Get the local time, assuming it starts from the given value.+--+-- Never inhibits. timeFrom :: Monad m => Time -> Wire m a Time timeFrom t' =
FRP/NetWire/Wire.hs view
@@ -12,8 +12,7 @@ WireState(..), -- * Auxilliary types- Event,- InhibitException,+ InhibitException(..), Output, SF, Time,@@ -23,6 +22,7 @@ inhibitEx, initWireState, mkGen,+ noEvent, toGen ) where@@ -32,6 +32,8 @@ import Control.Category import Control.Concurrent.STM import Control.Exception (Exception(..), SomeException)+import Control.Monad+import Control.Monad.Fix import Control.Monad.IO.Class import Data.Functor.Identity import Data.Typeable@@ -42,7 +44,7 @@ -- | Events are signals, which can be absent. They usually denote -- discrete occurences of certain events. -type Event = Maybe+--type Event = Maybe -- | Inhibition exception with an informative message. This exception@@ -56,8 +58,7 @@ instance Exception InhibitException --- | The output of a wire. When the wire inhibits, then this will be a--- 'Left' value with an exception.+-- | Functor for output signals. type Output = Either SomeException @@ -81,36 +82,37 @@ WId :: Wire m a a +-- | This instance corresponds to the 'ArrowPlus' and 'ArrowZero'+-- instances.+ instance Monad m => Alternative (Wire m a) where empty = zeroArrow (<|>) = (<+>) +-- | Applicative interface to signal networks.+ instance Monad m => Applicative (Wire m a) where pure = WConst wf' <*> wx' = WGen $ \ws x' -> do- (mf, wf) <- toGen wf' ws x'- (mx, wx) <- toGen wx' ws x'- return (mf <*> mx, wf <*> wx)+ (cf, wf) <- toGen wf' ws x'+ (cx, wx) <- toGen wx' ws x'+ return (cf <*> cx, wf <*> wx) +-- | Arrow interface to signal networks.+ instance Monad m => Arrow (Wire m) where arr = WArr - first (WGen f) =- WGen $ \ws (x', y) -> do- (mx, w) <- f ws x'- return (fmap (,y) mx, first w)+ first (WGen f) = WGen $ \ws (x', y) -> liftM (fmap (, y) *** first) (f ws x') first (WArr f) = WArr (first f) first (WConst c) = WArr (first (const c)) first WId = WId - second (WGen f) =- WGen $ \ws (x, y') -> do- (my, w) <- f ws y'- return (fmap (x,) my, second w)+ second (WGen f) = WGen $ \ws (x, y') -> liftM (fmap (x,) *** second) (f ws y') second (WArr f) = WArr (second f) second (WConst c) = WArr (second (const c)) second WId = WId@@ -119,59 +121,64 @@ WId *** wg = second wg wf' *** wg' = WGen $ \ws (x', y') -> do- (mx, wf) <- toGen wf' ws x'- (my, wg) <- toGen wg' ws y'- return (liftA2 (,) mx my, wf *** wg)+ (cx, wf) <- toGen wf' ws x'+ (cy, wg) <- toGen wg' ws y'+ return (liftA2 (,) cx cy, wf *** wg) wf' &&& wg' = WGen $ \ws x' -> do- (mx1, wf) <- toGen wf' ws x'- (mx2, wg) <- toGen wg' ws x'- return (liftA2 (,) mx1 mx2, wf &&& wg)+ (cx1, wf) <- toGen wf' ws x'+ (cx2, wg) <- toGen wg' ws x'+ return (liftA2 (,) cx1 cx2, wf &&& wg) +-- | Signal routing. Unused routes are frozen, until they are put back+-- into use.+ instance Monad m => ArrowChoice (Wire m) where left w' = wl where wl = WGen $ \ws mx' -> case mx' of- Left x' -> do- (mx, w) <- toGen w' ws x'- return (fmap Left mx, left w)- Right x -> return (Right (Right x), wl)+ Left x' -> liftM (fmap Left *** left) (toGen w' ws x')+ Right x -> return (pure (Right x), wl) right w' = wl where wl = WGen $ \ws mx' -> case mx' of- Right x' -> do- (mx, w) <- toGen w' ws x'- return (fmap Right mx, right w)- Left x -> return (Right (Left x), wl)+ Right x' -> liftM (fmap Right *** right) (toGen w' ws x')+ Left x -> return (pure (Left x), wl) wf' +++ wg' = WGen $ \ws mx' -> case mx' of- Left x' -> do- (mx, wf) <- toGen wf' ws x'- return (fmap Left mx, wf +++ wg')- Right x' -> do- (mx, wg) <- toGen wg' ws x'- return (fmap Right mx, wf' +++ wg)+ Left x' -> liftM (fmap Left *** (+++ wg')) (toGen wf' ws x')+ Right x' -> liftM (fmap Right *** (wf' +++)) (toGen wg' ws x') wf' ||| wg' = WGen $ \ws mx' -> case mx' of- Left x' -> do- (mx, wf) <- toGen wf' ws x'- return (mx, wf ||| wg')- Right x' -> do- (mx, wg) <- toGen wg' ws x'- return (mx, wf' ||| wg)+ Left x' -> liftM (second (||| wg')) (toGen wf' ws x')+ Right x' -> liftM (second (wf' |||)) (toGen wg' ws x') +-- | Value recursion. Warning: Recursive signal networks must never+-- inhibit. Use 'FRP.NetWire.Tools.exhibit' or 'FRP.NetWire.Event.event'.++instance MonadFix m => ArrowLoop (Wire m) where+ loop w' =+ WGen $ \ws x' -> do+ rec (Right (x, d), w) <- toGen w' ws (x', d)+ return (Right x, loop w)+++-- | Left-biased signal network combination. If the left arrow+-- inhibits, the right arrow is tried. If both inhibit, their+-- combination inhibits.+ instance Monad m => ArrowPlus (Wire m) where WGen f <+> wg = WGen $ \ws x' -> do@@ -187,12 +194,14 @@ WId <+> _ = WId +-- | The zero arrow always inhibits.+ instance Monad m => ArrowZero (Wire m) where- zeroArrow =- mkGen $ \_ _ ->- return (Left (inhibitEx "Signal inhibited"), zeroArrow)+ zeroArrow = mkGen $ \_ _ -> return (Left (inhibitEx "Signal inhibited"), zeroArrow) +-- | Identity signal network and signal network sequencing.+ instance Monad m => Category (Wire m) where id = WId @@ -235,6 +244,8 @@ w1 . WId = w1 +-- | Map over the result of a signal network.+ instance Monad m => Functor (Wire m a) where fmap f (WGen w') = WGen $ \ws x' -> do@@ -285,6 +296,13 @@ mkGen :: (WireState m -> a -> m (Output b, Wire m a b)) -> Wire m a b mkGen = WGen+++-- | Construct an 'InhibitException' wrapped in a 'SomeException' with a+-- message indicating that a certain event did not happen.++noEvent :: SomeException+noEvent = inhibitEx "No event" -- | Extract the transition function of a wire.
netwire.cabal view
@@ -1,5 +1,5 @@ Name: netwire-Version: 1.1.0+Version: 1.2.0 Category: FRP, Network Synopsis: Arrowized FRP implementation Maintainer: Ertugrul Söylemez <es@ertes.de>@@ -11,10 +11,10 @@ Stability: beta Cabal-version: >= 1.8 Description:- This library provides an arrowized functional reactive programming- (FRP) implementation. It is similar to Yampa and Animas, but has a- much simpler internal representation and a lot of new features.+ (FRP) implementation. From the basic idea it is similar to Yampa+ and Animas, but has a much simpler internal representation and a lot+ of new features. Library Build-depends:@@ -32,6 +32,7 @@ Extensions: Arrows DeriveDataTypeable+ FlexibleInstances GADTs RankNTypes ScopedTypeVariables@@ -57,12 +58,12 @@ -- Executable netwire-test -- Build-depends: -- base >= 4 && <= 5,--- gloss, -- netwire,--- time+-- transformers -- Extensions:--- Arrows,+-- Arrows -- ScopedTypeVariables+-- ViewPatterns -- Hs-Source-Dirs: test -- Main-is: Main.hs -- GHC-Options: -W -threaded -rtsopts