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