packages feed

reactive-0.5: src/Data/MEvent.hs

{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE TypeOperators, TypeSynonymInstances, MultiParamTypeClasses #-}

----------------------------------------------------------------------
-- |
-- Module      :  Data.MEvent
-- Copyright   :  (c) Conal Elliott 2008
-- License     :  BSD3
-- 
-- Maintainer  :  conal@conal.net
-- Stability   :  experimental
-- 
-- Event implementation via semantics & Maybe
----------------------------------------------------------------------

module Data.MEvent
  (
    -- * Event primitives
    Event', accumE
  ) where

import Data.Monoid
import Data.Maybe
import Control.Monad (MonadPlus(..))

-- TypeCompose
import Control.Compose ((:.)(..),inO,inO2)

import qualified Data.SEvent as SR  -- semantics


{----------------------------------------------------------
    Event primitives
----------------------------------------------------------}

-- | General events.  'Functor', 'Applicative', and 'Monoid' by
-- construction.  See also 'Event\''.
-- In this representation, an event is a list of time/maybe pairs.  The
-- 'Just's correspond to occurrences and the 'Nothing's to
-- non-occurrences.
type Event' t = SR.Event' t :. Maybe

-- The 'Monad' instance is thanks to Data.SEvent:
-- 
--   instance Ord t => DistribM (Event' t) Maybe where ...

-- TODO: revisit Phooey.  Can I use :. in place of monad transformers?
-- How to monad transformers relate to the monad instance of (:.)?
-- Follow up on references from my chat with Cale on 2008-03-02.

-- One of the standard Monoid instances for type compositions.  This one
-- interleaves occurrences.
instance Ord t => Monoid (Event' t a) where
  mempty  = O mempty
  mappend = inO2 mappend  -- interleave

-- This MonadPlus instance could go in EventExtras, but it would be an
-- orphan there.
instance Ord t => MonadPlus (Event' t) where { mzero = mempty; mplus = mappend }


-- | Accumulating event, starting from an initial value and a
-- update-function event.
accumE :: Ord t => a -> Event' t (a -> a) -> Event' t a
accumE a = inO $ fmap Just . SR.accumE a . fmap (fromMaybe id)

-- TODO: redefine accumE to preserve 'Nothing's, for later optimization.

-- (<*>) :: Fut (a->a) -> Fut a -> Fut a

-- (<*>) (on futures) does some unnecessary work here, since the function
-- is guaranteed to be at least as new as the argument.