I write docs for my iteratee-like library and I have problem with
lhs2tex. When I execute lhs2tex and then latex, I get a document with
long typesignatures and expressions expanded beyound page margins. I
attached a sourcefile I have problem with. Can someone give me an advise
how to force long signatures and expressions to be broken into multible
lines ?
This module contains basic types and combinators for building and processing streaming data
Note: any data constructor and field names may change. So, do NOT use them in your code, use only 
defined functions and instances.
\begin{code}
module Data.Iteration.Types where
\end{code}

We wish full-fledged monad transformers. This imports classes from transformers package.
\begin{code}
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
\end{code}

Enumerator is something that may provide input element or input tail. Enumerator is
newtype for monadic action, that can result in 
Nothing - no more input 
Just (Left someError) - error occured
Just (Right s, t) - some output provided and computation for source tail provided

\begin{code}
newtype Enumerator e s m
 = Enumerator 
	{ runEnumerator ::
		m (Maybe (Either e (s, Enumerator e s m) ) )
	}
\end{code}

the following function is a wrapper so resulting interface for different modules be compatible.
It gets three computations: what to do if no input, what to do on error and
how to produce one step of input. Tail of input is reduced in the same computation
\begin{code}
runE :: Monad m => Enumerator e s m -> m r -> (e -> m r) -> (s -> Enumerator e s m -> m r) -> m r
runE en pr eh sh = runEnumerator en >>= \v -> case v of
	Nothing			-> pr
	Just (Left e)		-> eh e
	Just (Right (s,e) )	-> sh s e
\end{code}


Enumeratee is a tool for building enumerator. It is separate from enumerators to not mess the logic. 
A way to embed computations in nested monad is needed. A nested monad appears in enumerator only, so
to lift from inner monad we have to enclose computation into resulting enumerator.
\begin{code}
newtype Enumeratee e s m a
 = Enumeratee 
 	{ runEnumeratee
		:: (a -> Enumerator e s m)
		-> Enumerator e s m 
	}
\end{code}

Of course, a way to build Enumerator from Enumeratee is needed. 
\begin{code}
mkE :: Enumeratee e s m (Enumerator e s m) -> Enumerator e s m
mkE e = runEnumeratee e id
\end{code}

A Monad and Functor instances for Continuation monad are adopted brain-free
\begin{code}
instance Monad (Enumeratee e s m) where
 return a = Enumeratee ($ a)
 m >>=  k = Enumeratee $ \c -> runEnumeratee m  $ \v -> runEnumeratee (k v) c

instance Functor (Enumeratee e s m) where
 fmap f m = m >>= return . f
\end{code}


To embed computation in inner monad, we have to dig into Enumerator as Enumeratee's newtype does not
contain explicit monadic computations. This implementation runs nested computation and then passes
result to continuation and opens newtype. 
\begin{code}
instance MonadTrans (Enumeratee e s) where
 lift m = Enumeratee $ \c -> Enumerator $ m >>= \v -> runEnumerator (c v)
\end{code}

A very traditional MonadIO instance, found as is in most monad transformers libraries.
\begin{code}
instance MonadIO m => MonadIO (Enumeratee e s m) where
 liftIO = lift. liftIO
\end{code}

The main part: yield a value. We postfix function with E (Enumeratee) to distinct from
similiar functions found later. 
\begin{code}
yieldE :: Monad m => s -> Enumeratee e s m ()
yieldE v = Enumeratee $ \c -> Enumerator $ return $ Just $ Right (v, c () )
\end{code}

finalE is final computations returns 'dummy' enumerator. It is designed to be
last computation in do-block in Enumerator specification. An alternative exists:
failE, that indicates an error in stream. 
\begin{code}
finalE :: Monad m => Enumeratee e s m (Enumerator e s m)
finalE = return $ Enumerator $ return Nothing

failE :: Monad m => e -> Enumeratee e s m (Enumerator e s m)
failE e = return $ Enumerator $ return $ Just $ Left e 
\end{code}

Iterator is something, that takes enumerator and produces value. Unlike Enumerator, Iterator
is in control: it reduces enumerator whenever needed. However, basic definitions follows the
same pattern.
\begin{code}
newtype Iterator r e s m 
 = Iterator 
 	{ runIterator 
		:: Enumerator e s m
		-> m r
	}

newtype Iteratee r e s m a
 = Iteratee 
 	{ runIteratee 
		:: (a -> Iterator r e s m)
		-> Iterator r e s m
	}

mkI :: Iteratee r e s m (Iterator r e s m) -> Iterator r e s m 
mkI i = runIteratee i id

instance Monad (Iteratee r e s m) where
 return a = Iteratee ($ a)
 m >>=  k = Iteratee $ \c -> runIteratee m $ \v -> runIteratee (k v) c

instance Functor (Iteratee r e s m) where
 fmap f m = m >>= return . f

instance MonadTrans (Iteratee r e s) where
 lift m = Iteratee $ \c -> Iterator $ \e -> m >>= \v -> runIterator (c v) e

instance MonadIO m => MonadIO (Iteratee r e s m) where
 liftIO = lift . liftIO
\end{code}

This function produces final iterator that does nothing and simply returns value provided
\begin{code}
finalI :: Monad m => r -> Iteratee r e s m (Iterator r e s m)
finalI r = return $ Iterator $ \_ -> return r
\end{code}

This is the main operation. As with yieldE, we have to dig into iterator. Sematic of operation is
clear: give action in underiling monad to execute if no input, give action to execute if error
occurs and you are free to describe tail of computation. 
\begin{code}
nextI :: Monad m => m r -> (e -> m r) -> Iteratee r e s m s
nextI pr eh = Iteratee $ \c -> Iterator $ \e -> runE e pr eh $ \s e' -> runIterator (c s) e'
\end{code}

----------------------------------------------------------------------------------------

One sometimes needs to transcode streams. This is not simple fmap operation for functors, but
a full fledged transformation, where one free to take any amount of input and produce any amount
of output. The simplest form of such transformation is lexing a source file.
\begin{code}
newtype Adapter eo ei so si m 
 = Adapter
 	{ runAdapter 
		:: Enumerator ei si m
		-> Enumerator eo so m
	}

\end{code}

yet again boring part.
\begin{code}
newtype Adaptee eo ei so si m a
 = Adaptee
 	{ runAdaptee 
		:: ( a -> Adapter eo ei so si m)
		-> Adapter eo ei so si m 
	}

mkA 	:: Adaptee eo ei so si m (Adapter eo ei so si m)
	-> Adapter eo ei so si m
mkA a = runAdaptee a id

instance Monad (Adaptee eo ei so si m) where
 return a = Adaptee ($ a)
 m >>=  k = Adaptee $ \c -> runAdaptee m $ \v -> runAdaptee (k v) c

instance Functor (Adaptee eo ei so si m) where
 fmap f m = m >>= return. f

instance MonadIO m => MonadIO (Adaptee eo ei so si m) where
 liftIO = lift . liftIO 

\end{code}

Lifting of computation in underling monad for Adaptee is slightly tricker. As both Adaptee and Adapter
does not contain monadic computations directly, we have to dig into Enumerator. 

\begin{code}
instance MonadTrans (Adaptee eo ei so si) where
 lift m = Adaptee $ \c -> Adapter $ \e -> Enumerator $ m >>= \v -> runEnumerator $ runAdapter (c v) e
\end{code}

taking input from enumerator follows the same pattern as for iteratee: give enumerator if no input,
give enumerator for error in input. And of cource, again digging into enumerator
\begin{code}
nextA 	:: Monad m 
	=> Enumerator eo so m 
	-> (ei -> Enumerator eo so m)
	-> Adaptee eo ei so si m si
nextA ote oeh = Adaptee $ \c -> Adapter $ \en -> Enumerator $ runEnumerator en >>= \cev -> case cev of
	Nothing 		-> runEnumerator ote
	Just (Left er)		-> runEnumerator $ oeh er
	Just (Right (v,st) )	-> runEnumerator $ runAdapter (c v) st
\end{code}

yielding a value is straight.
\begin{code}
yieldA 	:: Monad m 
	=> so 
	-> Adaptee eo ei so si m ()
yieldA v = Adaptee $ \c -> Adapter $ \e -> Enumerator $ return $ Just $ Right $ (v , runAdapter (c () ) e )
\end{code}

buiding final computation is simple: provide 'tail' and get final adapter, that drops any remaining input and
simply runs given enumerator
\begin{code}
finalA 	:: Monad m
	=> Enumerator eo so m 
	-> Adaptee eo ei so si m (Adapter eo ei so si m)
finalA e = return $ Adapter $ \_ -> e
\end{code}

Zipper is very similiar to Adapter: it takes two Enumerators and returns one Enumerator.
\begin{code}
data Zipper eo eli eri so sli sri m
 = Zipper
 	{ runZipper
		:: Enumerator eli sli m
		-> Enumerator eri sri m
		-> Enumerator eo so m 
	}
\end{code}
boring, boring, boring
\begin{code}
data Zippee eo eli eri so sli sri m a
 = Zippee
 	{ runZippee
		:: (a -> Zipper eo eli eri so sli sri m)
		-> Zipper eo eli eri so sli sri m
	}

mkZ     :: Zippee eo eli eri so sli sri m (Zipper eo eli eri so sli sri m)
        -> Zipper eo eli eri so sli sri m
mkZ z = runZippee z id


instance Monad (Zippee eo eli eri so sli sri m) where
 return a = Zippee ($ a)
 m >>=  k = Zippee $ \c -> runZippee m $ \v -> runZippee (k v) c

instance Functor (Zippee eo eli eri so sli sri m) where
 fmap f m = m >>= return . f

instance MonadIO m => MonadIO (Zippee eo eli eri so sli sri m) where
 liftIO = lift . liftIO 
\end{code}

to implement lifting from inner monad we again have to dig into Enumerator
\begin{code}
instance MonadTrans (Zippee eo eli eri so sli sri) where
 lift m = Zippee $ \c -> Zipper $ \len ren -> Enumerator $ m >>= \v -> runEnumerator $ runZipper (c v) len ren
\end{code}

Zipper has two operations for taking next elemen: take element from left stream (nextZl) and take 
element from right stream (nextZr). nextZl takes adapter for transcoding rest of the right stream if
no input and if error in left stream and reverse for nextZr.
\begin{code}
nextZl 	:: Monad m
	=> Adapter eo eri so sri m 
	-> (eli -> Adapter eo eri so sri m)
	-> Zippee eo eli eri so sli sri m sli
nextZl dra era = Zippee $ \c -> Zipper $ \len ren -> Enumerator $ runEnumerator len >>= \cev -> case cev of
	Nothing			-> runEnumerator $ runAdapter dra ren
	Just (Left e)		-> runEnumerator $ runAdapter (era e) ren
	Just (Right (v,lre) )	-> runEnumerator $ runZipper (c v) lre ren

nextZr	:: Monad m
	=> Adapter eo eli so sli m
	-> ( eri -> Adapter eo eli so sli m)
	-> Zippee eo eli eri so sli sri m sri
nextZr dla ela = Zippee $ \c -> Zipper $ \len ren -> Enumerator $ runEnumerator ren >>= \cev -> case cev of
	Nothing			-> runEnumerator $ runAdapter dla len
	Just (Left e)		-> runEnumerator $ runAdapter (ela e) len
	Just (Right (v,rre))	-> runEnumerator $ runZipper (c v) len rre
\end{code}

yieldZ is very similiar to yieldA
\begin{code}
yieldZ 	:: Monad m
	=> so
	-> Zippee eo eli eri so sli sri m ()
yieldZ so = Zippee $ \c -> Zipper $ \len ren -> Enumerator $ return $ Just $ Right $ (so, runZipper (c () ) len ren )
\end{code}

Zipper provides three finals:: one to drop both input streams, one to drop right and transcode only left
(finalZl) and one to drop left and transcode only right (finalZr)
\begin{code}
finalZ 	:: Monad m
	=> Enumerator eo so m
	-> Zippee eo eli eri so sli sri m (Zipper eo eli eri so sli sri m )
finalZ e = Zippee $ \c -> c $ Zipper $ \_ _ -> e

finalZl :: Monad m
	=> Adapter eo eli so sli m
	-> Zippee eo eli eri so sli sri m (Zipper eo eli eri so sli sri m)
finalZl a = Zippee $ \c -> c $ Zipper $ \len _ -> runAdapter a len

finalZr	:: Monad m
	=> Adapter eo eri so sri m
	-> Zippee eo eli eri so sli sri m (Zipper eo eli eri so sli sri m)
finalZr a = Zippee $ \c -> c $ Zipper $ \_ ren -> runAdapter a ren
\end{code}


Passive iterator is somthing, that encodes iteration, but has to be driven by
external function. It represents one step of folding, where next steps are encoded
as suspended monadic actions. This one has straighword design to imitate interface
of active iteratees.
\begin{code}
newtype IteratorP r e s m
 = IteratorP
 	{ runIteratorP ::  m ( Either (m r) (m r, e -> m r, s -> IteratorP r e s m) )
	}
\end{code}

boring, boring, boring
\begin{code}
newtype IterateeP r e s m a
 = IterateeP 
 	{ runIterateeP  :: (a -> IteratorP r e s m)
			-> IteratorP r e s m
	}

instance Monad (IterateeP r e s m) where
 return a = IterateeP ($ a)
 m >>=  k = IterateeP $ \c -> runIterateeP m $ \v -> runIterateeP (k v) c

instance Functor (IterateeP r e s m) where
 fmap f m = m >>= return . f

instance MonadTrans (IterateeP r e s) where
 lift m = IterateeP $ \c -> IteratorP $ m >>= \v -> runIteratorP $ c v

instance MonadIO m => MonadIO (IterateeP r e s m) where
 liftIO = lift . liftIO 
\end{code}

imitate interface for active iterators
\begin{code}
nextIP 	:: Monad m
	=> m r
	-> (e -> m r)
	-> IterateeP r e s m s
nextIP pr eh = IterateeP $ \c -> IteratorP $ return $ Right $ (pr, eh , c)


finalIP :: Monad m 
	=> r
	-> IterateeP r e s m (IteratorP r e s m)
finalIP r = IterateeP $ \c -> c $ IteratorP $ return $ Left $ return r
\end{code}

promote passive iterator to active one.
\begin{code}
ip2a 	:: Monad m
	=> IteratorP r e s m
	-> Iterator r e s m
ip2a i = Iterator $ \e -> do
	is <- runIteratorP i
	case is of
	 Left sa -> sa
	 Right (fa,eh,sh) -> runE e fa eh $ \s en -> runIterator (ip2a (sh s)) en
\end{code}


combine two passive iterators into one.
\begin{code}
parIP 	:: Monad m
	=> IteratorP r1 e s m
	-> IteratorP r2 e s m
	-> IteratorP (r1,r2) e s m
parIP i1 i2 = IteratorP $ do
	i1s <- runIteratorP i1
	i2s <- runIteratorP i2
	case (i1s,i2s) of
	 (Left m1s, Left m2s) -> do
	 	m1pr <- m1s
		m2pr <- m2s
		return $ Left $ return (m1pr,m2pr)
	 (Right (m1r,m1e,m1s), Left m2r) -> return $ Right 
	 	( m1r >>= \r1 -> m2r >>= \r2 -> return (r1,r2)
		, \e -> m1e e >>= \r1 -> m2r >>= \r2 -> return (r1,r2)
		, \s -> parIP (m1s s) (IteratorP $ return $ Left $ m2r)
		)
	 (Left m1r, Right (m2r,m2e,m2s) ) -> return $ Right
	 	( m1r >>= \r1 -> m2r >>= \r2 -> return (r1,r2)
		, \e -> m1r >>= \r1 -> m2e e >>= \r2 -> return (r1,r2)
		, \s -> parIP (IteratorP $ return $ Left $ m1r) (m2s s)
		)
	 (Right (m1r,m1e,m1s), Right (m2r,m2e,m2s) ) -> return $ Right
	 	( m1r >>= \r1 -> m2r >>= \r2 -> return (r1,r2)
		, \e -> m1e e >>= \r1 -> m2e e >>= \r2 -> return (r1,r2)
		, \s -> parIP (m1s s) (m2s s) 
		)

\end{code}

Future work:: addition of resource management helper support. 
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to