Pipes is actually bi directional.  However most common usage of pipes
is unidirectional where elements flow downstream.

When you have a unidirectional pipe what is actually happening is you
are sending elements downstream, and then you are sending () upstream
when you want another chunk.  The unidirectional pipe upstream from
you gets that () and uses that as a signal to send its next chunk back
downstream.

await and yield are actually implemented using the bidirectional pipe
functions request and respond. You can see this in the source where
they are defined as such:

yield :: Monad m => a -> Producer' a m ()
yield = respond

await :: Monad m => Consumer' a m a
await = request ()

Where respond takes the element sent downstream, and returns ().
Await sends () upstream and returns an element.



On Tue, May 9, 2017 at 11:59 AM, Yan Huang <yhu...@cs.umd.edu> wrote:
> Thanks, David! Your explanation helps. But one more question appears,
>
> Why isn't the Producer defined as follows
>       type Producer b = Proxy X () X b
> (where both ends of the upstream are assured to be blocked)
> or defined as
>       type Producer b = Proxy X X X b
> (where it is guaranteed that the producer can't take in anything from the
> source of the downstream)?
>
>
> On Tue, May 9, 2017 at 11:30 AM, David McBride <toa...@gmail.com> wrote:
>>
>> data X has no inhabitants.  () has exactly one inhabitant, which is ().
>>
>> This means that you can constuict a (), but you cannot construct an X.
>>
>> Inn practice with pipes that means that if a part of the Pipe type is
>> set to (), you can use yield () in your code.  But you cannot yield
>> (??? :: X) because X has no constructor.
>>
>> By the time you've connected a producer to a consumer you have a full
>> Effect type, it should not be sending items up or down stream, () or
>> otherwise, so it blocks off both of those variables in the Effect type
>> to force your code to adhere to that on the type level.
>>
>> On Tue, May 9, 2017 at 11:06 AM, Yan Huang <yhu...@cs.umd.edu> wrote:
>> > In the Appendix section of the tutorial
>> >
>> > (https://hackage.haskell.org/package/pipes-4.3.3/docs/Pipes-Tutorial.html),
>> > it defines an inhabited "data X" to mask the backward flow of the
>> > "Proxy"
>> > type. It seems that the null type "()" is also used for the same
>> > purpose,
>> > while the choice of X and () as a dummy type looks arbitrary. Are there
>> > any
>> > differences or am I missing something?
>> >
>> > Thanks!
>> >
>> > --
>> > 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 haskell-pipes+unsubscr...@googlegroups.com.
>> > To post to this group, send email to haskell-pipes@googlegroups.com.
>>
>> --
>> You received this message because you are subscribed to a topic in the
>> Google Groups "Haskell Pipes" group.
>> To unsubscribe from this topic, visit
>> https://groups.google.com/d/topic/haskell-pipes/gLSIj_E9RSc/unsubscribe.
>> To unsubscribe from this group and all its topics, send an email to
>> haskell-pipes+unsubscr...@googlegroups.com.
>> To post to this group, send email to haskell-pipes@googlegroups.com.
>
>
> --
> 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 haskell-pipes+unsubscr...@googlegroups.com.
> To post to this group, send email to haskell-pipes@googlegroups.com.

-- 
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 haskell-pipes+unsubscr...@googlegroups.com.
To post to this group, send email to haskell-pipes@googlegroups.com.

Reply via email to