packages feed

wires-0.1.0: Control/Wire/Core.hs

-- |
-- Copyright:  (c) 2016 Ertugrul Söylemez
-- License:    BSD3
-- Maintainer: Ertugrul Söylemez <esz@posteo.de>
-- Stability:  experimental

{-# LANGUAGE RankNTypes #-}

module Control.Wire.Core
    ( -- * Wires
      Wire,
      evalWith,
      initial,
      withM,

      -- * Events
      Event,
      catMapE,
      hold,
      hold',
      never,
      unfoldE,

      -- * Switching
      manage,
      manage',
      sequenceW,
      switch,
      switch'
    )
    where

import Control.Wire.Internal


-- | Map and filter event occurrences using the given function.

catMapE :: (a -> Maybe b) -> Event a -> Event b
catMapE f = event NotNow (maybe NotNow Now . f)


-- | Evaluate the input using the given strategy in every frame.  Valid
-- arguments include functions like `seq`.

evalWith :: (Applicative m) => (forall b. a -> b -> b) -> Wire m a a
evalWith strat = let w = Wire (\x -> x `strat` pure (x, w)) in w


-- | Hold the latest occurrence of the given event starting with the
-- given initial value.  The value switch occurs in the next frame.

hold :: (Applicative m) => a -> Wire m (Event a) a
hold x' = delayW x' (hold' x')


-- | Hold the latest occurrence of the given event starting with the
-- given initial value.  The value switch occurs instantly.

hold' :: (Applicative m) => a -> Wire m (Event a) a
hold' x' = Wire $ (\x -> pure (x, hold' x)) . event x' id


-- | Run the given action once at the beginning.

initial :: (Applicative m) => Wire m (m a) a
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.

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)
manage ws' =
    Wire $ \(x, mf) ->
        (\ys -> (fst <$> ys,
                 manage (event id 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.

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)
manage' ws' =
    Wire $ \(x, mf) ->
        (\ys -> (fst <$> ys,
                 manage (snd <$> ys)))
        <$> traverse (`stepWire` x) (event id id mf ws')


-- | The event that never occurs.

never :: Event a
never = NotNow


-- | Sequence each of the given wires and collect their results.

sequenceW :: (Traversable f, Applicative m) => f (Wire m a b) -> Wire m a (f b)
sequenceW ws' =
    Wire $ \x ->
        (\ys -> (fst <$> ys,
                 sequenceW (snd <$> ys)))
        <$> traverse (\w' -> stepWire w' x) ws'


-- | Acts like the given wire until its event occurs, then switches to
-- the wire the occurrence contained.  The switch occurs in the next
-- frame.

switch :: (Functor m) => Wire m a (b, Event (Wire m a b)) -> Wire m a b
switch w' =
    Wire $ \x ->
        (\((y, mw), w) -> (y, event (switch w) id mw))
        <$> stepWire w' x


-- | Acts like the given wire until its event occurs, then switches to
-- the wire the occurrence contained.  The switch occurs immediately.

switch' :: (Monad m) => Wire m a (b, Event (Wire m a b)) -> Wire m a b
switch' w' =
    Wire $ \x -> do
        ((y, mw), w) <- stepWire w' x
        case mw of
          NotNow -> pure (y, switch w)
          Now nw -> stepWire nw x


-- | Unfold the given event using the state transition functions it
-- carries.

unfoldE :: (Applicative m) => s -> Wire m (Event (s -> (a, s))) (Event a)
unfoldE s' =
    Wire $ \mf ->
        pure (case mf of
                NotNow -> (NotNow, unfoldE s')
                Now f  -> let (x, s) = f s' in (Now x, unfoldE s))


-- | Run the given action to initialise the given wire.  Example:
--
-- > withM (scan f) actionFromInitialInput

withM :: (Monad m) => (s -> Wire m a b) -> (a -> m s) -> Wire m a b
withM w f =
    Wire $ \x -> do
        s0 <- f x
        stepWire (w s0) x