Avoiding exporting constructors

32 views
Skip to first unread message

Chris Smith

unread,
Jun 7, 2012, 2:23:39 PM6/7/12
to streamin...@googlegroups.com
We've had a few conversations on Reddit and here about exposing too
much implementation detail, about the resulting observable differences
that seem to violate monad transformer laws, and the like. So I spent
some time thinking about that issue. Just exposing await (or
tryAwait) and yield primitives is clearly not powerful enough, as
simple things like:

rightP :: Pipe a b m r -> Pipe (Either c a) (Either c b) m r

cannot be defined in those terms. One must fall back to pattern
matching on the constructors. Upon further thought, I realized that
the root of the problem is that runPipe is too limited. So I wrote
this... here I'm using the 5-parameter pipes without finalization to
keep things simple, but the same idea applies to others as well, I
believe.

simulatePipe :: (Monad m, MonadTrans t, Monad (t m))
=> t m (Either r a)
-> (b -> t m ())
-> Pipe a b r m s
-> t m s
simulatePipe up down (Yield p x) = down x >> simulatePipe up down p
simulatePipe up down (Await f) = simulatePipe up down . f =<< up
simulatePipe up down (Do m) = lift m >>= simulatePipe up down
simulatePipe up down (Done x) = return x

runPipe :: Monad m => Pipe () Void r m s -> m s
runPipe = runIdentityT . simulatePipe (return (Right ()))
(error "runPipe: impossible
yield of Void")

And at that point, one can define, for example:

leftP :: Monad m => Pipe a b r m s -> Pipe (Either a c) (Either b c) r m s
leftP p = simulatePipe up down p
where up = do x <- tryAwait
case x of Left r -> return (Left r)
Right (Left x) -> return (Right x)
Right (Right x) -> yield (Right x) >> up
down = yield . Left

Because simulatePipe requires a MonadTrans instance that comes with
certain laws, this dodges the complaint about (lift . return /=
return) that has come up in the past, and it lets you nicely run an
incomplete pipeline . Yet it should let you build pretty much any
desired pipe. This seems like an improvement to me.

Comments?

Michael Snoyman

unread,
Jun 8, 2012, 5:38:14 AM6/8/12
to streamin...@googlegroups.com

> --
> You received this message because you are subscribed to the Google Groups "streaming-haskell" group.
> To post to this group, send email to streamin...@googlegroups.com.
> To unsubscribe from this group, send email to streaming-hask...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/streaming-haskell?hl=en.
>

I don't think we're ever going to entirely get away from exposing the constructors, but having more comprehensive high-level functions seems like a good move to me. I'd be concerned that once you add in finalization and leftovers, though, its going to become unwieldy.

Michael

Reply all
Reply to author
Forward
0 new messages