wires 0.1.0 → 0.2.0
raw patch · 9 files changed
+194/−47 lines, 9 filesdep +mtldep ~deepseqdep ~profunctorsdep ~semigroupoidsnew-component:exe:wires-feedback
Dependencies added: mtl
Dependency ranges changed: deepseq, profunctors, semigroupoids, these
Files
- CHANGELOG.md +17/−0
- Control/Wire.hs +2/−0
- Control/Wire/Core.hs +37/−13
- Control/Wire/Internal.hs +22/−22
- Control/Wire/Trans.hs +36/−0
- Control/Wire/Utils.hs +34/−2
- examples/Utils.hs +1/−2
- examples/feedback.hs +23/−0
- wires.cabal +22/−8
CHANGELOG.md view
@@ -1,3 +1,20 @@+# 0.2.0++ * **Breaking change**: Safer API for `manage` and `manage'`.++ * Fix: Wire strictness. Strict value recursion like the following+ works now:++ rec x <- scan x0 -< x `seq` ev++ * Change: Tighter version bounds.++ * Add: `splitE`, `unalignE`, `unlessE`.++ * Add: `hoistW`.++ * Add: `asksW`, `askW`, `runReaderW`.+ # 0.1.0 * Initial version.
Control/Wire.hs view
@@ -8,10 +8,12 @@ ( -- * Wires module Control.Category, module Control.Wire.Core,+ module Control.Wire.Trans, module Control.Wire.Utils ) where import Control.Category import Control.Wire.Core+import Control.Wire.Trans import Control.Wire.Utils
Control/Wire/Core.hs view
@@ -22,17 +22,30 @@ unfoldE, -- * Switching+ Switch(..), manage, manage', sequenceW, switch,- switch'+ switch',++ -- * Monad transformers+ hoistW ) where import Control.Wire.Internal +-- | Functions to be applied to the current set of wires managed by+-- 'manage'.++newtype Switch f m a b =+ Switch {+ fromSwitch :: forall s. (Wire m a b -> s) -> f s -> f s+ }++ -- | Map and filter event occurrences using the given function. catMapE :: (a -> Maybe b) -> Event a -> Event b@@ -46,6 +59,17 @@ evalWith strat = let w = Wire (\x -> x `strat` pure (x, w)) in w +-- | Map the underlying monad using the given function.++hoistW :: (Functor m) => (a -> a') -> (forall x. a -> m' x -> m x) -> Wire m' a' b -> Wire m a b+hoistW f trans = go+ where+ go w' =+ Wire $ \x ->+ (\(y, w) -> (y, go w))+ <$> trans x (stepWire w' (f x))++ -- | Hold the latest occurrence of the given event starting with the -- given initial value. The value switch occurs in the next frame. @@ -66,34 +90,34 @@ initial = Wire $ fmap (\y -> (y, pure y)) --- | Sequence each of the given wires and collect their results. If the--- given event occurs, the its function is applied to the current set of--- wires. Changes are applied in the next frame.+-- | Sequence each of the given wires and collect their results.+-- Whenever the given event occurs its function is applied to the+-- current set of wires. Changes are applied in the next frame. manage :: (Traversable f, Applicative m) => f (Wire m a b)- -> Wire m (a, Event (f (Wire m a b) -> f (Wire m a b))) (f b)+ -> Wire m (a, Event (Switch f m a b)) (f b) manage ws' = Wire $ \(x, mf) -> (\ys -> (fst <$> ys,- manage (event id id mf (snd <$> ys))))+ manage (event id (\(Switch f) -> f id) mf (snd <$> ys)))) <$> traverse (`stepWire` x) ws' --- | Sequence each of the given wires and collect their results. If the--- given event occurs, the its function is applied to the current set of--- wires. Changes are applied immediately.+-- | Sequence each of the given wires and collect their results.+-- Whenever the given event occurs its function is applied to the+-- current set of wires. Changes are applied immediately. manage' :: (Traversable f, Applicative m) => f (Wire m a b)- -> Wire m (a, Event (f (Wire m a b) -> f (Wire m a b))) (f b)+ -> Wire m (a, Event (Switch f m a b)) (f b) manage' ws' = Wire $ \(x, mf) -> (\ys -> (fst <$> ys,- manage (snd <$> ys)))- <$> traverse (`stepWire` x) (event id id mf ws')+ manage' (snd <$> ys)))+ <$> traverse (`stepWire` x) (event id (\(Switch f) -> f id) mf ws') -- | The event that never occurs.@@ -131,7 +155,7 @@ Wire $ \x -> do ((y, mw), w) <- stepWire w' x case mw of- NotNow -> pure (y, switch w)+ NotNow -> pure (y, switch' w) Now nw -> stepWire nw x
Control/Wire/Internal.hs view
@@ -1,5 +1,5 @@ -- |--- Copyright: (c) 2016 Ertugrul Söylemez+-- Copyright: (c) 2017 Ertugrul Söylemez -- License: BSD3 -- Maintainer: Ertugrul Söylemez <esz@posteo.de> -- Stability: experimental@@ -91,7 +91,7 @@ wf' <*> wx' = Wire $ \x' ->- (\(f, wf) (x, wx) -> (f x, wf <*> wx))+ (\ ~(f, wf) ~(x, wx) -> (f x, wf <*> wx)) <$> stepWire wf' x' <*> stepWire wx' x' @@ -102,7 +102,7 @@ wx' &&& wy' = Wire $ \x' ->- (\(x, wx) (y, wy) -> ((x, y), wx &&& wy))+ (\ ~(x, wx) ~(y, wy) -> ((x, y), wx &&& wy)) <$> stepWire wx' x' <*> stepWire wy' x' @@ -118,13 +118,13 @@ wl' +++ wr' = Wire $- either (\x -> (\(y, wl) -> (Left y, wl +++ wr')) <$> stepWire wl' x)- (\x -> (\(y, wr) -> (Right y, wl' +++ wr)) <$> stepWire wr' x)+ either (\x -> (\ ~(y, wl) -> (Left y, wl +++ wr')) <$> stepWire wl' x)+ (\x -> (\ ~(y, wr) -> (Right y, wl' +++ wr)) <$> stepWire wr' x) wl' ||| wr' = Wire $- either (\x -> (\(y, wl) -> (y, wl ||| wr')) <$> stepWire wl' x)- (\x -> (\(y, wr) -> (y, wl' ||| wr)) <$> stepWire wr' x)+ either (\x -> (\ ~(y, wl) -> (y, wl ||| wr')) <$> stepWire wl' x)+ (\x -> (\ ~(y, wr) -> (y, wl' ||| wr)) <$> stepWire wr' x) instance (MonadFix m) => ArrowLoop (Wire m) where loop = unfirst@@ -134,52 +134,52 @@ w2' . w1' = Wire $ \x0 -> do- (x1, w1) <- stepWire w1' x0- (x2, w2) <- stepWire w2' x1+ ~(x1, w1) <- stepWire w1' x0+ ~(x2, w2) <- stepWire w2' x1 pure (x2, w2 . w1) instance (Applicative m) => Choice (Wire m) where left' w' = Wire $- either (\x -> (\(y, w) -> (Left y, left' w)) <$> stepWire w' x)+ either (\x -> (\ ~(y, w) -> (Left y, left' w)) <$> stepWire w' x) (\x -> pure (Right x, left' w')) right' w' = Wire $ either (\x -> pure (Left x, right' w'))- (\x -> (\(y, w) -> (Right y, right' w)) <$> stepWire w' x)+ (\x -> (\ ~(y, w) -> (Right y, right' w)) <$> stepWire w' x) instance (MonadFix m) => Costrong (Wire m) where unfirst w' = Wire $ \x' ->- (\((x, _), w) -> (x, unfirst w))+ (\ ~(x, w) -> (fst x, unfirst w)) <$> mfix (\r -> stepWire w' (x', snd (fst r))) unsecond w' = Wire $ \x' ->- (\((_, x), w) -> (x, unsecond w))+ (\ ~(x, w) -> (snd x, unsecond w)) <$> mfix (\r -> stepWire w' (fst (fst r), x')) instance (Functor m) => Profunctor (Wire m) where dimap fl fr = go where- go w' = Wire (fmap (\(y, w) -> (fr y, go w)) . stepWire w' . fl)+ go w' = Wire (fmap (\ ~(y, w) -> (fr y, go w)) . stepWire w' . fl) lmap f = go where- go w' = Wire (fmap (\(y, w) -> (y, go w)) . stepWire w' . f)+ go w' = Wire (fmap (\ ~(y, w) -> (y, go w)) . stepWire w' . f) rmap = fmap instance (Functor m) => Strong (Wire m) where first' w' =- Wire $ \(x', y) ->- (\(x, w) -> ((x, y), first' w))+ Wire $ \ ~(x', y) ->+ (\ ~(x, w) -> ((x, y), first' w)) <$> stepWire w' x' second' w' =- Wire $ \(x, y') ->- (\(y, w) -> ((x, y), second' w))+ Wire $ \ ~(x, y') ->+ (\ ~(y, w) -> ((x, y), second' w)) <$> stepWire w' y' @@ -187,9 +187,9 @@ delayW :: (Functor m) => b -> Wire m a b -> Wire m a b delayW y' w' =- Wire $ \x ->- (\(y, w) -> (y', delayW y w))- <$> stepWire w' x+ Wire $+ fmap (\(y, w) -> (y', delayW y w)) .+ stepWire w' -- | Fold the given event.
+ Control/Wire/Trans.hs view
@@ -0,0 +1,36 @@+-- |+-- Copyright: (c) 2016 Ertugrul Söylemez+-- License: BSD3+-- Maintainer: Ertugrul Söylemez <esz@posteo.de>++module Control.Wire.Trans+ ( -- * Monad transformers+ -- ** Reader+ asksW,+ askW,+ runReaderW+ )+ where++import Control.Monad.Reader+import Control.Wire.Controller+import Control.Wire.Core+import Data.Profunctor+++-- | Get the given function applied to the environment value.++asksW :: (MonadReader a m) => Wire m (a -> b) b+asksW = lmap asks animate+++-- | Get the environment value.++askW :: (MonadReader b m) => Wire m a b+askW = lmap (\_ -> ask) animate+++-- | Embed the given 'ReaderT'-transformed monad.++runReaderW :: (Functor m) => Wire (ReaderT e m) a b -> Wire m (e, a) b+runReaderW = hoistW snd (\(env, _) c -> runReaderT c env)
Control/Wire/Utils.hs view
@@ -1,5 +1,5 @@ -- |--- Copyright: (c) 2016 Ertugrul Söylemez+-- Copyright: (c) 2017 Ertugrul Söylemez -- License: BSD3 -- Maintainer: Ertugrul Söylemez <esz@posteo.de> -- Stability: experimental@@ -12,13 +12,19 @@ filterE, scan, scan',- scanE+ scanE,+ splitE,+ unalignE,+ unlessE ) where import Control.Category import Control.Wire.Core+import Control.Wire.Internal+import Data.Align import Data.Profunctor+import Data.These import Prelude hiding ((.), id) @@ -45,6 +51,32 @@ scanE :: (Applicative m) => a -> Wire m (Event (a -> a)) (Event a) scanE = lmap (fmap $ \f x -> let y = f x in (y, y)) . unfoldE+++-- | Split the given event++splitE :: Event (Either a b) -> (Event a, Event b)+splitE NotNow = (NotNow, NotNow)+splitE (Now (Left x)) = (Now x, NotNow)+splitE (Now (Right y)) = (NotNow, Now y)+++-- | Split the given event+--+-- Inverse of 'align'.++unalignE :: Event (These a b) -> (Event a, Event b)+unalignE NotNow = (NotNow, NotNow)+unalignE (Now (This x)) = (Now x, NotNow)+unalignE (Now (That y)) = (NotNow, Now y)+unalignE (Now (These x y)) = (Now x, Now y)+++-- | Event difference: like the left event, but only when the right+-- event doesn't occur at the same time.++unlessE :: Event a -> Event b -> Event a+unlessE mx my = catMapE justThis (align mx my) -- | Run the given action to initialise the given wire. Simplified
examples/Utils.hs view
@@ -20,8 +20,7 @@ -- occurrences. average :: (Fractional a, Monad m) => Int -> Wire m (Event a) (Event a)-average n =- lmap (fmap go) (unfoldE Seq.empty)+average n = lmap (fmap go) (unfoldE Seq.empty) where go x xs' = let xs = Seq.take n (x Seq.<| xs')
+ examples/feedback.hs view
@@ -0,0 +1,23 @@+-- |+-- Copyright: (c) 2017 Ertugrul Söylemez+-- License: BSD3+-- Maintainer: Ertugrul Söylemez <esz@posteo.de>++{-# LANGUAGE Arrows #-}++module Main (main) where++import Control.Concurrent+import Control.Wire+import Control.Wire.Controller+++main :: IO ()+main =+ control $ proc _ -> do+ ev <- newEvent -< do+ Just () <$ threadDelay 500000++ rec x <- scan 1 -< x `seq` (+ x) <$ ev++ animate -< never <$ print x
wires.cabal view
@@ -1,11 +1,11 @@ name: wires-version: 0.1.0+version: 0.2.0 category: Control, FRP synopsis: Functional reactive programming library maintainer: Ertugrul Söylemez <esz@posteo.de> author: Ertugrul Söylemez <esz@posteo.de>-copyright: Copyright 2016 Ertugrul Söylemez+copyright: Copyright 2017 Ertugrul Söylemez homepage: https://github.com/esoeylemez/wires bug-reports: https://github.com/esoeylemez/wires/issues license: BSD3@@ -29,20 +29,34 @@ library build-depends:- base >= 4.8 && < 5,- deepseq >= 1.4 && < 2,- profunctors >= 5.2 && < 6,- semigroupoids >= 5.1 && < 6,- these >= 0.7 && < 1+ base >= 4.8 && < 5,+ deepseq == 1.4.*,+ mtl >= 2.0 && < 2.3,+ profunctors >= 5.0 && < 5.3,+ semigroupoids >= 5.0 && < 5.2,+ these == 0.7.* default-language: Haskell2010- ghc-options: -W -fdefer-typed-holes+ ghc-options: -W exposed-modules: Control.Wire Control.Wire.Controller Control.Wire.Core Control.Wire.Internal+ Control.Wire.Trans Control.Wire.Utils Control.Wire.Varying++executable wires-feedback+ if flag(examples)+ build-depends:+ base >= 4.8 && < 5,+ wires+ else+ buildable: False+ default-language: Haskell2010+ ghc-options: -threaded -fdefer-typed-holes+ hs-source-dirs: examples+ main-is: feedback.hs executable wires-ping-pong if flag(examples)