TypeCompose-0.1: src/Control/DataDriven.hs
{-# OPTIONS -fglasgow-exts #-}
----------------------------------------------------------------------
-- |
-- Module : Control.DataDriven
-- Copyright : (c) Conal Elliott 2007
-- License : LGPL
--
-- Maintainer : conal@conal.net
-- Stability : experimental
-- Portability : portable
--
-- Data-driven computations
----------------------------------------------------------------------
module Control.DataDriven
(
-- * Plumbing for \"events\" and subscription
Sink, Action, News
-- * Data-driven computations
, DataDrivenG, dd, mapCur
, DataDriven, runDD, joinDD
) where
import Control.Applicative
import Control.Monad (join)
import Control.Arrow (second)
import Data.Monoid
import Control.Compose
{----------------------------------------------------------
Plumbing for event publishing
----------------------------------------------------------}
-- | Sinks (consumers) of values
type Sink cur a = a -> Action cur
-- | Actions
type Action cur = cur ()
-- | News publisher -- somewhere to register updaters to be executed
-- when events occur.
type News cur = Sink cur (Action cur)
{----------------------------------------------------------
Data-driven computations
----------------------------------------------------------}
-- | The general type of data-driven computations. Represented as a
-- /news/ publisher (@news@) and a way to get new values (@cur@). Clients
-- interested in the value subscribe to @news@ and extract a new value
-- from @cur@ when notified that the value may have changed. When @news@
-- is a monoid and @cur@ is an applicative functor, @DataDrivenG news cur@
-- is an applicative functor also. The applicative property is very
-- convenient for composition. See the more specific type 'DataDriven'.
--
-- Nicer, but Haddock chokes on the infix op:
-- type DataDrivenG news cur = ((,) news) `O` cur
type DataDrivenG news cur = O ((,) news) cur
-- More tersely :
-- type DataDrivenG news = O ((,) news)
-- | Construct a data-driven computation from a subscription service
-- (@Monoid@) and a value source subscriber (@Applicative@).
dd :: cur a -> news -> DataDrivenG news cur a
dd = flip (curry O)
-- | Modify the source part of a 'DataDriven' computation.
mapCur :: (cur a -> cur b) -> (DataDrivenG news cur a -> DataDrivenG news cur b)
mapCur f = inO (second f)
-- | Data driven with news publisher
type DataDriven cur = DataDrivenG (News cur) cur
-- | Run a unit-valued 'DataDriven' computation. Causes the source to be
-- executed /and/ registered with the subscriber.
runDD :: (Monoid (Action cur), Applicative cur)
=> DataDriven cur () -> Action cur
runDD (O (news,cur)) = news cur `mappend` cur
-- | Apply 'join' to a source
joinDD :: Monad cur => DataDriven cur (cur a) -> DataDriven cur a
joinDD = mapCur join
-- runDDJoin :: (Monad cur, Applicative cur, Monoid (Action cur))
-- => DataDriven cur (Action cur) -> Action cur
-- runDDJoin = runDD . joinDD