\subsubsection{Time ordered lists}

The time is stored in differences between the events.
(cf. \secref{discussion:performance-reltime})

\begin{haskelllisting}

> module Haskore.Basic.TimeOrderedList 
>    (T, Immediate,
>     mapBodyM, mapM, mapM_, getBodies,
>     mapBody, mapTime,
>     mapTimeTail,
>     empty, singleton, null, viewL, viewTimeL, viewBodyL, cons, snoc,
>     consBody, consTime,
>     append, concat, cycle,
>     insert, decreaseStart, delay, partition, foldr, slice, normalize,
>     collectCoincident, flatten, mapCoincident,
>     resample, toAbsoluteEventList,
>     run, runTimeStamp, runTimeStampGrouped,
>     runCore, runRelative, runRelativeCore,
>     segmentBefore, toPairList, toAbsPairList, attachTime,
>    ) where
>
> import Data.EventList.Relative.TimeBody
> import Data.EventList.Relative.MixedBody
> import qualified Data.EventList.Relative.BodyBody as BodyBody
> import qualified Data.EventList.Absolute.TimeBody as AbsList
>
> import qualified Haskore.General.Utility as Utility
> import qualified Data.List as List
>
> import qualified Haskore.Basic.Timer as Timer
> import qualified Numeric.NonNegative.Class as NonNeg
> import qualified Numeric.NonNegative.Wrapper as NonNegW
>
> import qualified Control.Monad as Monad
> import Control.Monad.Trans (MonadIO, liftIO)

> import Prelude hiding (null, foldr, mapM, mapM_, concat, cycle)

\end{haskelllisting}

\begin{haskelllisting}

> type Immediate time body = BodyBody.T time body

\end{haskelllisting}

\begin{haskelllisting}

> segmentBefore :: (body -> Bool) -> T time body -> [T time body]
> segmentBefore p =
>    map fromPairList .
>    Utility.segmentBefore (p . snd) .
>    toPairList

\end{haskelllisting}


\subsubsection{Run actions according to a time ordered lists}

The first function assumes,
that the action does not consume time
and that the wait command is precise.
It is not very useful in practice, but very simple.

\begin{haskelllisting}

> runRelative :: (NonNeg.C time, RealFrac time, MonadIO io) =>
>    Timer.T -> (body -> io a) -> T time body -> io [a]
> runRelative timer action =
>    runRelativeCore timer action .
>    resample (fromIntegral $ Timer.resolution timer)

> runRelativeCore :: MonadIO io =>
>    Timer.T -> (body -> io a) -> T NonNegW.Integer body -> io [a]
> runRelativeCore timer action =
>    Monad.liftM getBodies .
>    mapM (liftIO . Timer.wait timer) action

\end{haskelllisting}

The next set of routines is more precise.
It computes a time table starting with current system time
and tries to stick to it.

So far, I worked hard to use time differences instead of absolute times
in order to avoid increasing memory consumption of time numbers
(which however slows down as time evolves)
but the time related functions of the system are absolute,
so have to make our ones absolute as well.

\begin{haskelllisting}

> run :: (RealFrac time, MonadIO io) =>
>    Timer.T -> (body -> io a) -> T time body -> io [a]
> run timer action = runTimeStamp timer (const action)

\end{haskelllisting}

The wait calls are necessarily quantized,
but the time passed to the action is not quantized.

\begin{haskelllisting}

> runTimeStamp :: (RealFrac time, MonadIO io) =>
>    Timer.T -> (time -> body -> io a) -> T time body -> io [a]
> runTimeStamp =
>    runCore id

\end{haskelllisting}

This routine is only necessary,
because differences might be too small
to be noticed in the absolute time values.
That is, collectCoincident will split events which actually belong together.

\begin{haskelllisting}

> runTimeStampGrouped :: (RealFrac time, MonadIO io) =>
>    Timer.T -> (time -> [body] -> io a) -> T time body -> io [a]
> runTimeStampGrouped =
>    runCore AbsList.collectCoincident

> runCore :: (Fractional time0, RealFrac time1, MonadIO io) =>
>    (AbsList.T time0 body0 -> AbsList.T time1 body1) ->
>    Timer.T -> (time1 -> body1 -> io a) -> T time0 body0 -> io [a]
> runCore convertAbs timer action evs =
>    Monad.liftM AbsList.getBodies .
>    AbsList.mapM
>       (liftIO . Timer.waitUntilSeconds timer)
>       (uncurry action) .
>    attachTime .
>    convertAbs .
>    flip toAbsoluteEventList evs =<<
>    liftIO (Timer.getTimeSeconds timer)

> toAbsPairList :: AbsList.T time body -> [(time, body)]
> toAbsPairList = AbsList.toPairList

> fromAbsPairList :: [(time, body)] -> AbsList.T time body
> fromAbsPairList = AbsList.fromPairList

> attachTime :: AbsList.T time body -> AbsList.T time (time, body)
> attachTime =
>    fromAbsPairList .
>    map (\ ~(time,body) -> (time, (time,body))) .
>    toAbsPairList

\end{haskelllisting}

%    AbsList.foldr
%       (\t (b,xs) -> AbsList.cons t (t,b) xs)
%       (,)
%       AbsList.empty
