packages feed

spanout-0.1: src/Spanout/Wire.hs

{-# LANGUAGE Arrows #-}

module Spanout.Wire
  ( constM
  , bindW
  , accum
  , accumE
  , switch
  , forThen

  , Wire
  , Wire.Timed(..)
  , Wire.stepWire
  , Wire.delay
  , Wire.time
  ) where

import Control.Arrow
import Control.Monad
import Control.Wire (Wire)
import qualified Control.Wire as Wire

import Data.Monoid



-- A reactive value from a monadic value
constM :: Monad m => m b -> Wire s e m a b
constM m = Wire.mkGen_ . const $ liftM Right m

-- Peforms a monadic action and parametrizes a wire with the resulting value
bindW :: (Monad m, Monoid s) => m k -> (k -> Wire s e m a b) -> Wire s e m a b
bindW mk f = Wire.mkGen $ \s a -> do
  k <- mk
  Wire.stepWire (f k) s (Right a)

-- A wire that yields an accumulated value based on its input and a time delta
accum :: Wire.HasTime t s => (t -> b -> a -> b) -> b -> Wire s e m a b
accum f b = Wire.mkSF $ \s a ->
  let b' = f (Wire.dtime s) b a
  in  (b', accum f b')

-- A wire that yields an accumulated value based on events
accumE :: (b -> a -> b) -> b -> Wire s e m (Maybe a) b
accumE f b = Wire.mkSFN $ \ma ->
  case ma of
    Just a  ->
      let b' = f b a
      in  (b', accumE f b')
    Nothing -> (b, accumE f b)

-- Switches from a wire that produces either an output or a new wire
switch :: (Monoid s, Monad m)
  => Wire s e m a (Either (Wire s e m a b) b) -> Wire s e m a b
switch w = Wire.mkGen $ \s a -> do
  (Right eb, w') <- Wire.stepWire w s (Right a)
  case eb of
    Left w'' -> Wire.stepWire w'' mempty (Right a)
    Right b -> return (Right b, switch w')

-- Acts as the identity wire for given time, then yield a constant value
forThen :: (Wire.HasTime t s, Monad m) => t -> k -> Wire s e m a (Either k a)
forThen t e = proc a -> do
  t' <- Wire.time -< ()
  returnA -<
    if t' < t
    then Right a
    else Left e