Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why does Source use () instead of Void as the leftover type? #62

Closed
aristidb opened this issue Aug 14, 2012 · 10 comments
Closed

Why does Source use () instead of Void as the leftover type? #62

aristidb opened this issue Aug 14, 2012 · 10 comments

Comments

@aristidb
Copy link
Contributor

Either I'm misunderstanding something, or Source could perfectly well use Void as the leftover type (if there is no input, there can also be no leftovers). Similarly, I suppose the input type could be Void too.

Why is this not so?

@aristidb
Copy link
Contributor Author

OK, it is clear now why the input type needs to be (), not Void, because NeedInput needs an input value. But the same does not hold for the leftovers.

@snoyberg
Copy link
Owner

Unifying the leftover and input types keeps the function types consistent among Source, Conduit, and Sink.

@aristidb
Copy link
Contributor Author

Doesn't it prevent using runPipe? What's the advantage of the consistent types?

@aristidb
Copy link
Contributor Author

Example:

runPipe ((undefined :: Source IO Int) `pipeL` (undefined :: Sink Int IO ()))

I expect this to type-check, but it does not.

@aristidb
Copy link
Contributor Author

Oh, I need to use injectLeftovers on both sides. Although that does not make a lot of sense to me, leftovers in a Source.

@snoyberg snoyberg reopened this Aug 14, 2012
@snoyberg
Copy link
Owner

My comment about consistent types no longer applies. In the past, the type signature for pipeL was:

pipeL :: Monad m => Pipe a a b r0 m r1 -> Pipe b b c r1 m r2 -> Pipe a a c r0 m r2

in which case the () for leftover in Source was a requirement. So in theory, we could change this to Void now without breaking any of the existing functions.

However, I'm not really sure I see a reason to. I like the fact that in the conduit types (Source, Sink, and Conduit) input and leftover is always the same. I can't think of a practical benefit besides consistency, but in theory it could allow people to implement nicer functions on top of it.

Is there a real downside to the current choice? Certainly it's a bit ridiculous to provide leftovers in a Source, but then again requesting input in a source is just as inane.

@aristidb
Copy link
Contributor Author

I can think of two things:

  1. There might be a performance penalty when composing in fancy ways and having to run injectLeftovers on the source. Because injectLeftovers doesn't actually make sense for sources, but has to be called because of the type. This is not a problem usually because you side-stepped the problem in ($$) by using connectResume.
  2. It just feels wrong to me.

@snoyberg
Copy link
Owner

For point (1): if you're using anything besides ($$), you should really be using GSource instead. And with GSource, the leftover type is required to be free, which is equivalent to specifying it as Void. As for (2), I understand your reasons, but it feels worse to me to have a disparity between the different types.

@aristidb
Copy link
Contributor Author

Fair enough. I have the feeling that this points to a more fundamental issue with the NeedInput constructor for source-like pipes, though. I think it is a logical error if a source has a NeedInput constructor, and currently this is handled gracefully but perhaps there is a nicer way. Let me think about it!

@snoyberg
Copy link
Owner

I actually consider it one of the downsides to moving to the unified datatype. One thing I played around with a bit was using a GADT for Pipe and statically disallowing some stuff (e.g., NeedInput for Sources, HaveOutput for Sinks, and Leftover whenever leftovers were not enabled), but it seemed to complicate things too much.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants