iteratee Using monad-control in enumerators

Bas van Dijk v.dijk.bas at gmail.com
Fri Sep 23 13:04:45 BST 2011


Hello,

I would like to propose using controlIO (from monad-control) in the
definition of enumFd and friends.

One of the advantages of using controlIO is that you can use control
operators like allocaBytes which are (far?) more efficient that the
manual mallocBytes and free. Another advantage is that you need fewer
"liftings" of IO actions into 'm' (I only need one controlIO per
iteration of the loop):

---------------------------------------------------------------------
import Control.Monad.IO.Control

type Run s m a = Stream s -> IO (m (Iteratee s m a))

enumFd :: forall s el m a
       .  (NullPoint s, ReadableChunk s el, MonadControlIO m)
       => Int
       -> Fd
       -> Enumerator s m a
enumFd bs fd = \iter ->
    controlIO $ \runInIO -> do
      let bufsize = bs * (sizeOf (undefined :: el))
      allocaBytes bufsize $ \p ->
          let loop :: Enumerator s m a
              loop i = runIter i idoneM onCont

              onCont :: (Stream s -> Iteratee s m a)
                     -> Maybe SomeException
                     -> m (Iteratee s m a)
              onCont _ (Just e) = return $ throwErr e
              onCont k Nothing =
                  controlIO $ \runInIO' -> do

                    let stop, cont :: Run s m a
                        stop = return   . return . k
                        cont = runInIO' . loop   . k

                    n <- myfdRead fd (castPtr p)
                                     (fromIntegral bufsize)
                    case n of
                      Left  _  -> stop $ EOF $ Just
                                    (error "myfdRead failed")
                      Right 0  -> do yield -- Why is this needed?
                                     stop $ Chunk empty
                      Right n' -> readFromPtr p (fromIntegral n') >>=
                                    cont . Chunk
          in runInIO $ loop iter
---------------------------------------------------------------------

Note that I already use this approach in usb-iteratee[1].

Finally note that this change does not require Iteratee to be an
instance of MonadControlIO.

What do you think?

Bas

[1] http://hackage.haskell.org/package/usb-iteratee



More information about the Iteratee mailing list