Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is `http` in http-enumerator an Iteratee?

The type signature for http is:

http :: MonadIO m
     => Request m
     -> (W.Status -> W.ResponseHeaders -> Iteratee S.ByteString m a)
     -> Manager
     -> Iteratee S.ByteString m a

Why isn't it this instead?

http :: MonadIO m => … -> m a

If I understand correctly, an Iteratee x m a is like a monadic parser that consumes a stream of items of type x. It makes sense for http's callback to be an Iteratee, as it consumes the response body.

However, http itself does not appear to consume any input. The httpLbs function executes http with run_ (defined in Data.Enumerator). From what I can tell, run considers it an error if the iteratee given to it expects input:

-- | Run an iteratee until it finishes, and return either the final value
-- (if it succeeded) or the error (if it failed).
run :: Monad m => Iteratee a m b
    -> m (Either Exc.SomeException b)
run i = do
    mStep <- runIteratee $ enumEOF ==<< i
    case mStep of
        Error err -> return $ Left err
        Yield x _ -> return $ Right x
        Continue _ -> error "run: divergent iteratee"

So if http does not consume input, why is it an iteratee? Why isn't it just a MonadIO action?

like image 259
Joey Adams Avatar asked Oct 03 '11 17:10

Joey Adams


1 Answers

  1. It's not an error to pass run (or run_) an Iteratee that expects input; that's why we first pass in enumEOF. It's invalid for an Iteratee to continue expecting input after receiving an EOF.
  2. By leaving the result of http in the Iteratee monad, you can perform multiple actions in the same pipeline, such as streaming two HTTP responses into a file.
like image 175
Michael Snoyman Avatar answered Oct 21 '22 10:10

Michael Snoyman