[Haskell-cafe] ANNOUNCE: pipes-core 0.1.0

Paolo Capriotti p.capriotti at gmail.com
Tue Apr 17 15:38:25 CEST 2012

On Mon, Apr 16, 2012 at 10:13 PM, Ben Franksen <ben.franksen at online.de> wrote:
> I like your pipes package. This is very similar to what Mario Blažević wrote
> about his Coroutines in the Monad.Reader (can't remember which issue; great
> article, BTW, many thanks Mario for making me understand the iteratee
> business (and also generators) for the first time). Your pipes-core looks
> even simpler to use, maybe due to avoiding to make a type distinction
> between consumer/producer/pipe (except the natural one i.e. through the
> input/output types), even though the parameterization by a functor (as in
> Monad.Coroutine) has its own beauty.

Yes, Mario Blažević's Transducer is the main inspiration for the
original pipes package, and consequently pipes-core.

> Two issues:
> (1) What is the reason for the asymmetry in
>  type Producer b m = Pipe () b m
>  type Consumer a m = Pipe a Void m
> i.e. why does Producer use () for the input? I would expect it to use Void,
> like Consumer does for its output. Calling await in a Producer resulting in
> an immediate 'return ()' as you say is allowed (in the tutorial) strikes me
> as not very useful.

The underlying reason for the asymmetry is the fact that '()' is a
terminal object in the category of haskell types and *total*
functions, while 'Void' is an initial object.

Here's a property that uniquely determines the definitions of
'Producer' above. Let 'X' be the type such that 'Producer b m = Pipe X
b m'. For all producers 'p' there should be a unique (total) pipe
'alpha :: forall a r. Pipe a X m r' such that 'alpha >+> p' and 'p'
are observationally equal. In other words, since a producer "never
uses values of its input type 'a'", there should be a unique way to
make it into a pipe which is polymorphic in 'a'. It's easy to see that
this property immediately implies that 'X' should be a terminal
object, i.e. '()', and 'alpha' is therefore 'pipe (const ())'.

Dually, you obtain that 'Consumer a m' is necessarily 'Pipe a Void m',
and 'alpha = pipe absurd'.

> (2) The $$ operator is poorly named. I would intuitively expect an operator
> that looks so similar to the standard $ to have the same direction of data
> flow (i.e. right to left, like function application and composition) but
> your is left to right. You could use e.g. >$> instead, which has the
> additional advantage of allowing a symmetric variant for the other direction
> i.e. <$<.

'$$' is inspired by iteratees. Similarly to its iteratee counterpart,
it discards upstream result values and only returns the output of the
last pipe. That said, '>$>' looks like a clearer alternative, so I
could consider changing it.

Thanks for your feedback!


More information about the Haskell-Cafe mailing list