On Thu, Jan 30, 2014 at 3:30 PM, Dan Burton <[email protected]> wrote:

Yes -- I agree with the how/why it works the way that it does.

> The reason that the "resumable" pipe resumes is because it pushes the pipe
> state tracking down into the IO monad.
>
> In short, pipes do not have resumability, so what you have done is added
> resumability by utilizing specific capabilities of the underlying monad (in
> this case IO, but you could do the same thing with ST or State).

Right. pipes itself does not supply any resumability feature. But some
Producers have that behavior implicitly -- via the underlying IO monad
or other mechanisms.

> You seem to imply that this is a problem with pipes generally, because
> running the same pipe multiple times might have unexpected effects. I
> instead see it as a problem with adding resumability to pipes, or other such
> dangerous effects, and that is what makes a given pipe behave in potentially
> unexpected ways.

I'm not suggesting it is a problem with pipes. Just that it is not
obvious at first (even though it perhaps should be). It is important
for people to realize that if you write code that expects the Producer
to have resuming behavior -- then you are going to be surprised when
you pass in a pure Producer. When you really think about it -- it
seems somewhat trivial. But -- I think it is easy to overlook when you
get tangled up in Pipes. If you sit down and start writing code that
is drawing data over the network from the beginning -- you may not
realize that you are relying on the Producer to 'remember' how much
has been consumed already until you try to pass in a pure Producer
later. Obviously, the Producer doesn't explicitly remember anything in
that case -- it is merely an artifact of the underlying IO that is
producing the results. I think it is easy to overlook which aspects
Producers do *not* abstract away.

But this still leaves me with questions. If I want to write an HTTP
server, should I assume that the Producer supplying the incoming data
is going to support 'resuming' and then use IORefs to fake it for pure
producers. Or should I assume purity by default and have the resuming
automatically baked into the system. Having a pure core seems better
in theory for testing and reasoning. But going IO seems like a better
choice for real world performance.

I guess part of my queasiness is that if I provide you a function like:


serveHTTP :: (Monad m) =>
             Producer ByteString m ()
          -> Consumer ByteString m ()
          -> (Request -> m Response)
          ->  m ()

I feel like it is natural to expect that you can do something like:

test = serveHTTP (yield dummyRequest) P.print myHandler

If you pass in a Producer where the ByteString is an invalid HTTP
request -- then you shouldn't be too surprised that you get an error.

But if you pass in a valid HTTP request like that and it fails because
serveHTTP is expecting the producer to 'resume' -- then I think it
will be pretty mysterious?

Now, we could run into the same problem in plain old IO if I had:

serverHTTP :: IO ByteString -- ^ get next chunk
           -> (ByteString -> IO ()) -- ^ send next chunk
           -> (Request -> IO Response)
           -> IO ()

and I do, (return dummyRequest), then I am essentially in the same
situation. Not sure why I feel differently about that. Perhaps because
we simply don't write a lot of functions with callbacks like that in
Haskell most of the time -- but in the Pipes world, it is a lot more
natural to try to wire up different Producers to the input of the
pipe?

Anyway, I don't think this is a problem with pipes itself. But more a
question of with path to go in using them in hyperdrive -- IO vs
StateT. I have to pick one -- and the choice is not obvious.

I have implemented a dummy prototype using the StateT method already,
I am working on an IO based version now. Perhaps when I have both
versions available, that will help make for clearer questions...

- jeremy

-- 
You received this message because you are subscribed to the Google Groups 
"Haskell Pipes" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].

Reply via email to