netwire-5.0.0: Control/Wire/Core.hs
-- |
-- Module: Control.Wire.Core
-- Copyright: (c) 2013 Ertugrul Soeylemez
-- License: BSD3
-- Maintainer: Ertugrul Soeylemez <es@ertes.de>
module Control.Wire.Core
( -- * Wires
Wire(..),
stepWire,
-- * Constructing wires
mkConst,
mkEmpty,
mkGen,
mkGen_,
mkGenN,
mkId,
mkPure,
mkPure_,
mkPureN,
mkSF,
mkSF_,
mkSFN,
-- * Data flow and dependencies
delay,
evalWith,
force,
forceNF,
-- * Utilities
(&&&!),
(***!),
lstrict,
mapWire
)
where
import qualified Data.Semigroup as Sg
import Control.Applicative
import Control.Arrow
import Control.Category
import Control.DeepSeq hiding (force)
import Control.Monad
import Control.Monad.Fix
import Control.Parallel.Strategies
import Data.Monoid
import Data.String
import Prelude hiding ((.), id)
-- | A wire is a signal function. It maps a reactive value to another
-- reactive value.
data Wire s e m a b where
WArr :: (Either e a -> Either e b) -> Wire s e m a b
WConst :: Either e b -> Wire s e m a b
WGen :: (s -> Either e a -> m (Either e b, Wire s e m a b)) -> Wire s e m a b
WId :: Wire s e m a a
WPure :: (s -> Either e a -> (Either e b, Wire s e m a b)) -> Wire s e m a b
instance (Monad m, Monoid e) => Alternative (Wire s e m a) where
empty = WConst (Left mempty)
w1' <|> w2' =
WGen $ \ds mx' ->
liftM2 (\(mx1, w1) (mx2, w2) -> lstrict (choose mx1 mx2, w1 <|> w2))
(stepWire w1' ds mx')
(stepWire w2' ds mx')
where
choose mx1@(Right _) _ = mx1
choose _ mx2@(Right _) = mx2
choose (Left ex1) (Left ex2) = Left (ex1 <> ex2)
instance (Monad m) => Applicative (Wire s e m a) where
pure = WConst . Right
wf' <*> wx' =
WGen $ \ds mx' ->
liftM2 (\(mf, wf) (mx, wx) -> lstrict (mf <*> mx, wf <*> wx))
(stepWire wf' ds mx')
(stepWire wx' ds mx')
instance (Monad m) => Arrow (Wire s e m) where
arr f = WArr (fmap f)
first w' =
WGen $ \ds mxy' ->
liftM (\(mx, w) -> lstrict (liftA2 (,) mx (fmap snd mxy'), first w))
(stepWire w' ds (fmap fst mxy'))
instance (Monad m, Monoid e) => ArrowChoice (Wire s e m) where
left w' =
WGen $ \ds mmx' ->
liftM (fmap Left ***! left) .
stepWire w' ds $
case mmx' of
Right (Left x) -> Right x
Right (Right _) -> Left mempty
Left ex -> Left ex
right w' =
WGen $ \ds mmx' ->
liftM (fmap Right ***! right) .
stepWire w' ds $
case mmx' of
Right (Right x) -> Right x
Right (Left _) -> Left mempty
Left ex -> Left ex
wl' +++ wr' =
WGen $ \ds mmx' ->
case mmx' of
Right (Left x) -> do
liftM2 (\(mx, wl) (_, wr) -> lstrict (fmap Left mx, wl +++ wr))
(stepWire wl' ds (Right x))
(stepWire wr' ds (Left mempty))
Right (Right x) -> do
liftM2 (\(_, wl) (mx, wr) -> lstrict (fmap Right mx, wl +++ wr))
(stepWire wl' ds (Left mempty))
(stepWire wr' ds (Right x))
Left ex ->
liftM2 (\(_, wl) (_, wr) -> lstrict (Left ex, wl +++ wr))
(stepWire wl' ds (Left ex))
(stepWire wr' ds (Left ex))
wl' ||| wr' =
WGen $ \ds mmx' ->
case mmx' of
Right (Left x) -> do
liftM2 (\(mx, wl) (_, wr) -> lstrict (mx, wl ||| wr))
(stepWire wl' ds (Right x))
(stepWire wr' ds (Left mempty))
Right (Right x) -> do
liftM2 (\(_, wl) (mx, wr) -> lstrict (mx, wl ||| wr))
(stepWire wl' ds (Left mempty))
(stepWire wr' ds (Right x))
Left ex ->
liftM2 (\(_, wl) (_, wr) -> lstrict (Left ex, wl ||| wr))
(stepWire wl' ds (Left ex))
(stepWire wr' ds (Left ex))
instance (MonadFix m) => ArrowLoop (Wire s e m) where
loop w' =
WGen $ \ds mx' ->
liftM (fmap fst ***! loop) .
mfix $ \ ~(mx, _) ->
let d | Right (_, d) <- mx = d
| otherwise = error "Feedback broken by inhibition"
in stepWire w' ds (fmap (, d) mx')
instance (Monad m, Monoid e) => ArrowPlus (Wire s e m) where
(<+>) = (<|>)
instance (Monad m, Monoid e) => ArrowZero (Wire s e m) where
zeroArrow = empty
instance (Monad m) => Category (Wire s e m) where
id = WId
w2' . w1' =
WGen $ \ds mx0 -> do
(mx1, w1) <- stepWire w1' ds mx0
(mx2, w2) <- stepWire w2' ds mx1
mx2 `seq` return (mx2, w2 . w1)
instance (Monad m, Floating b) => Floating (Wire s e m a b) where
(**) = liftA2 (**)
acos = fmap acos
acosh = fmap acosh
asin = fmap asin
asinh = fmap asinh
atan = fmap atan
atanh = fmap atanh
cos = fmap cos
cosh = fmap cosh
exp = fmap exp
log = fmap log
logBase = liftA2 logBase
pi = pure pi
sin = fmap sin
sinh = fmap sinh
sqrt = fmap sqrt
tan = fmap tan
tanh = fmap tanh
instance (Monad m, Fractional b) => Fractional (Wire s e m a b) where
(/) = liftA2 (/)
recip = fmap recip
fromRational = pure . fromRational
instance (Monad m) => Functor (Wire s e m a) where
fmap f (WArr g) = WArr (fmap f . g)
fmap f (WConst mx) = WConst (fmap f mx)
fmap f (WGen g) = WGen (\ds -> liftM (fmap f ***! fmap f) . g ds)
fmap f WId = WArr (fmap f)
fmap f (WPure g) = WPure (\ds -> (fmap f ***! fmap f) . g ds)
instance (Monad m, IsString b) => IsString (Wire s e m a b) where
fromString = pure . fromString
instance (Monad m, Monoid b) => Monoid (Wire s e m a b) where
mempty = pure mempty
mappend = liftA2 mappend
instance (Monad m, Num b) => Num (Wire s e m a b) where
(+) = liftA2 (+)
(-) = liftA2 (-)
(*) = liftA2 (*)
abs = fmap abs
negate = fmap negate
signum = fmap signum
fromInteger = pure . fromInteger
instance (Monad m, Sg.Semigroup b) => Sg.Semigroup (Wire s e m a b) where
(<>) = liftA2 (Sg.<>)
-- | Left-strict version of '&&&' for functions.
(&&&!) :: (a -> b) -> (a -> c) -> (a -> (b, c))
(&&&!) f g x' =
let (x, y) = (f x', g x')
in x `seq` (x, y)
-- | Left-strict version of '***' for functions.
(***!) :: (a -> c) -> (b -> d) -> ((a, b) -> (c, d))
(***!) f g (x', y') =
let (x, y) = (f x', g y')
in x `seq` (x, y)
-- | This wire delays its input signal by the smallest possible
-- (semantically infinitesimal) amount of time. You can use it when you
-- want to use feedback ('ArrowLoop'): If the user of the feedback
-- depends on /now/, delay the value before feeding it back. The
-- argument value is the replacement signal at the beginning.
--
-- * Depends: before now.
delay :: a -> Wire s e m a a
delay x' = mkSFN $ \x -> (x', delay x)
-- | Evaluate the input signal using the given 'Strategy' here. This
-- wire evaluates only produced values.
--
-- * Depends: now.
evalWith :: Strategy a -> Wire s e m a a
evalWith s =
WArr $ \mx ->
case mx of
Right x -> (x `using` s) `seq` mx
Left _ -> mx
-- | Force the input signal to WHNF here. This wire forces both
-- produced values and inhibition values.
--
-- * Depends: now.
force :: Wire s e m a a
force =
WArr $ \mx ->
case mx of
Right x -> x `seq` mx
Left ex -> ex `seq` mx
-- | Force the input signal to NF here. This wire forces only produced
-- values.
--
-- * Depends: now.
forceNF :: (NFData a) => Wire s e m a a
forceNF =
WArr $ \mx ->
case mx of
Right x -> x `deepseq` mx
Left _ -> mx
-- | Left-strict tuple.
lstrict :: (a, b) -> (a, b)
lstrict (x, y) = x `seq` (x, y)
-- | Apply the given monad morphism to the wire's underlying monad.
mapWire ::
(Monad m', Monad m)
=> (forall a. m' a -> m a)
-> Wire s e m' a b
-> Wire s e m a b
mapWire _ (WArr g) = WArr g
mapWire _ (WConst mx) = WConst mx
mapWire f (WGen g) = WGen (\ds -> liftM (lstrict . second (mapWire f)) . f . g ds)
mapWire _ WId = WId
mapWire f (WPure g) = WPure (\ds -> lstrict . second (mapWire f) . g ds)
-- | Construct a stateless wire from the given signal mapping function.
mkConst :: Either e b -> Wire s e m a b
mkConst = WConst
-- | Construct the empty wire, which inhibits forever.
mkEmpty :: (Monoid e) => Wire s e m a b
mkEmpty = mkConst (Left mempty)
-- | Construct a stateful wire from the given transition function.
mkGen :: (Monad m, Monoid s) => (s -> a -> m (Either e b, Wire s e m a b)) -> Wire s e m a b
mkGen f = loop mempty
where
loop s' =
WGen $ \ds mx ->
let s = s' <> ds in
s `seq`
case mx of
Left ex -> return (Left ex, loop s)
Right x' -> liftM lstrict (f s x')
-- | Construct a stateless wire from the given transition function.
mkGen_ :: (Monad m) => (a -> m (Either e b)) -> Wire s e m a b
mkGen_ f = loop
where
loop =
WGen $ \_ mx ->
case mx of
Left ex -> return (Left ex, loop)
Right x -> liftM (lstrict . (, loop)) (f x)
-- | Construct a stateful wire from the given transition function.
mkGenN :: (Monad m) => (a -> m (Either e b, Wire s e m a b)) -> Wire s e m a b
mkGenN f = loop
where
loop =
WGen $ \_ mx ->
case mx of
Left ex -> return (Left ex, loop)
Right x' -> liftM lstrict (f x')
-- | Construct the identity wire.
mkId :: Wire s e m a a
mkId = WId
-- | Construct a pure stateful wire from the given transition function.
mkPure :: (Monoid s) => (s -> a -> (Either e b, Wire s e m a b)) -> Wire s e m a b
mkPure f = loop mempty
where
loop s' =
WPure $ \ds mx ->
let s = s' <> ds in
s `seq`
case mx of
Left ex -> (Left ex, loop s)
Right x' -> lstrict (f s x')
-- | Construct a pure stateless wire from the given transition function.
mkPure_ :: (a -> Either e b) -> Wire s e m a b
mkPure_ f = WArr $ (>>= f)
-- | Construct a pure stateful wire from the given transition function.
mkPureN :: (a -> (Either e b, Wire s e m a b)) -> Wire s e m a b
mkPureN f = loop
where
loop =
WPure $ \_ mx ->
case mx of
Left ex -> (Left ex, loop)
Right x' -> lstrict (f x')
-- | Construct a pure stateful wire from the given signal function.
mkSF :: (Monoid s) => (s -> a -> (b, Wire s e m a b)) -> Wire s e m a b
mkSF f = mkPure (\ds -> lstrict . first (Right) . f ds)
-- | Construct a pure stateless wire from the given function.
mkSF_ :: (a -> b) -> Wire s e m a b
mkSF_ f = WArr (fmap f)
-- | Construct a pure stateful wire from the given signal function.
mkSFN :: (a -> (b, Wire s e m a b)) -> Wire s e m a b
mkSFN f = mkPureN (lstrict . first (Right) . f)
-- | Perform one step of the given wire.
stepWire :: (Monad m) => Wire s e m a b -> s -> Either e a -> m (Either e b, Wire s e m a b)
stepWire w@(WArr f) _ mx' = return (f mx', w)
stepWire w@(WConst mx) _ mx' = return (mx' *> mx, w)
stepWire (WGen f) ds mx' = f ds mx'
stepWire w@WId _ mx' = return (mx', w)
stepWire (WPure f) ds mx' = return (f ds mx')