Quantcast

A Question on dummy types

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

A Question on dummy types

Yan Huang
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!

--
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: A Question on dummy types

David McBride
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 <[hidden email]> 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!
>
> --
>
> "Haskell Pipes" group.
>
> email to [hidden email].
>

--



Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: A Question on dummy types

Yan Huang
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 <[hidden email]> 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 <[hidden email]> 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!
>
> --
> > "Haskell Pipes" group.
>
> email to [hidden email].
>
--
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 [hidden email].

--
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: A Question on dummy types

David McBride
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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.
>> >
>> > an
>> > email to [hidden email].
>> >
>>
>> --
>> 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
>> [hidden email].
>>
>
>
> --
>
> "Haskell Pipes" group.
>
> email to [hidden email].
>

--



Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: A Question on dummy types

Gabriel Gonzalez
The reason we don't define:

      type Producer b = Proxy X () X b

... is because you can't actually create a (useful) `Producer` of that type.  If you had a `Producer` of that type then the return value of `respond` (which is like `yield` but with a more general type) would be `X` which could be transformed into value of any type, but that's not possible unless you cheat and return `undefined` or something similar.  The only `Producer` that can have that type (without cheating) is one that never `yield`s or `respond`s.

That's also the same reason why we don't define:

      type Producer b = Proxy X X X b

As long as the third type parameter is `X` you can't `respond` or `yield`


On Tue, May 9, 2017 at 9:56 AM, David McBride <[hidden email]> wrote:
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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.
>> > >> > an
>> > email to [hidden email].
>> > >>
>> --
>> 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
>> [hidden email].
>> >
>
> --
> > "Haskell Pipes" group.
> > email to [hidden email].
>
--

--
Loading...