I have a value body :: BS.ByteString (ResourceT IO) (), from a function based on BS.readFile. I want to stream that value as the response body from a Wai Application. There's a helper, streamingResponse that takes a value of the type Stream (Of ByteString) IO r. I'm able to convert my BS.ByteString (ResourceT IO) () to Stream (Of ByteString) (ResourceT IO) () through the use of BS.toChunks, but it contains an extra ResourceT monad layer. Passing the body to streamingResponse gives me:
Couldn't match type ‘ResourceT IO’ with ‘IO’
Expected type: Stream (Of ByteString) IO ()
Actual type: Stream (Of ByteString) (ResourceT IO) ()
I've tried various things like wrapping things in runResourceT, binding and hoisting values etc. but really have no idea how to proceed. Here's the line in the full project if extra context is required.
Update0
hoist runResourceT body seems to type check. Someone also referred me to a Haskell Pipes thread, which may be a very related problem, and possible hint toward a solution.
If we want to allow
Streams that live inResourceT, we can do without the functions from streaming-wai (that only work forStreams based onIO) and instead build on top of functions likeresponseStreamfrom network-wai:streamingBodyhas typeStreamingBody, which is actually a type synonym for a function(Builder -> IO ()) -> IO () -> IO ()that takes a write callback and a flush callback as parameters, and uses them to write the response using some source of data that is in scope. (Note that these callbacks are provided by WAI, not by the user.)In our case, the source of data is a
Streamthat lives inResourceT. We need to lift the write and flush callbacks (that live inIO) usingliftIO, an also remember to invokerunResourceTto return a plainIOaction at the end.What if we wanted to flush the response only after the accumulated length of the emitted bytestrings reached some limit?
We would need a function (not implemented here) to create a division each time the limit is reached:
And then we could intercalate the flushing action between each group using
intercalates, before writing the stream: