CollectionB - generic behavioral collections.

\begin{code}
module CollectionB where
import FranCore
import MapG
import BVar
import IOExts

\end{code}

A generic behavioral collection is defined as a CollectionB. 
This is a combination of an event giving incremental updates,
and a behavior that represents the value of the collection over
time. It is therefore parameterised over the update operation,
the type of collection, and the type of values in the collection.


\begin{code}
data CollectionB b c a = CollectionB {eventC :: Event (b a),
		 	       	      behaviorC :: Behavior (c a)}

\end{code}

We define a type class for collection updates. This allows a number of
generic collection operations to be defined. We should be able to 
update a collection based on an update value (using applyOp) and
reset the collection using (resetOp).

\begin{code}

class CollectionOp b c where
 applyOp :: b a -> c a -> c a
 resetOp :: c a -> b a

\end{code}

We make a collection by accumulating with an initial static collection ls,
and updates based on the update event.

\begin{code}

newCollectionB :: CollectionOp b c => 
	         Event (b a) -> c a 
	      -> IO (CollectionB b c a)
newCollectionB e ls = do
 b <- stepAccum ls (e ==> applyOp)
 return $! CollectionB e b

\end{code}

We can merge collections given a merge function to merge two static 
collections, and a newly merged update event.
\begin{code}
mergeCB :: CollectionB b c a -> CollectionB b c a
        -> Event (b a) -> (c a -> c a -> c a) 
        -> CollectionB b c a
mergeCB c1 c2 mergeE mergeC = 
 CollectionB {eventC = mergeE,
              behaviorC = lift2 mergeC (behaviorC c1) (behaviorC c2)}

\end{code}

Mapping functions over behavior collections. 

\begin{code}
instance (Functor c,Functor b) => Functor (CollectionB b c) where
 fmap = mapC

instance (MapG e a b IO,MapG c a b IO,CollectionOp e c) =>
         MapG (CollectionB e c) a b IO where
 mapG = mapIOC


\end{code}

To map a normal function over an event we map over the update event and the
behavior. This will be inefficient if the map function is particularly complex
and both the update event and behavior are used a lot. But it seems to work ok,
for most examples I have tried.

\begin{code}
mapC :: (Functor c, Functor b) => (a -> d) -> CollectionB b c a 
      -> CollectionB b c d
mapC f (CollectionB e c) = 
      CollectionB (e ==> fmap f) 
                  (lift1 (fmap f) c)


\end{code}

To map an IO action over a collection. We make a new collection formed by
sampling the current value of the collection, mapping the IO action over 
the update event, and then generating a new collection. This has the 
alternative efficiency problem that we are ignoring the behavior bh, 
but the weak pointer stuff should generally cause bh to be garbage collected,
and so stop the unnecessary work being done for it. 

\begin{code}
mapIOC :: (MapG e a b IO,MapG c a b IO,CollectionOp e c)
       => (a -> IO b) -> CollectionB e c a 
       -> IO (CollectionB e c b)
mapIOC f (CollectionB e bh) = do
  t <- getFranTime 
  vs <-  bh `at` t
  init <- mapG f vs
  e' <- return $! withIOE e (mapG f)
  newCollectionB  e' init

\end{code}

To make a collection switcher, that changes between collections received
on an event. We start out with the current collection and then make the 
update event using switcherE. When the collection changes we sample the new
collection, and send a reset operation.

\begin{code}
instance CollectionOp b c => SwitchableM (CollectionB b c a) IO where
 mkSwitcher = switcherC

switcherC :: CollectionOp b c => (CollectionB b c a) -> Event (CollectionB b c a) -> IO (CollectionB b c a)
switcherC c1 e = do
   t <- getFranTime
   s <- behaviorC c1 `at` t
   (Wire l ev) <- newWire
   addListener (eventC c1 `switcherE'` e ==> eventC) l
   addListener e (comapIOL (\c -> do t <- getFranTime
				     vs <- behaviorC c `at` t
			 	     return $ resetOp vs) 
			    l)
   newCollectionB ev s
\end{code}
