Restrict type in phantom data-type

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Baa
Reply | Threaded
Open this post in threaded view
|

Restrict type in phantom data-type

Baa
Hello, List!

For example, I have specialized (right nameis phantom?) type:

  data Day a = Day { ... no `a` here }
  data Sunny
  data Rainy

  joyToday :: Day Sunny -> IO ()
  joyToday day = ...

  melancholyToday :: Day Rainy -> IO ()
  melancholyToday day = ...

And I can create (in spite of that it's phantom) some day:

  let day1 = Day {...} :: Day Sunny
  joyToday day1

but no problem to create `Day Int`, `Day Char`, etc which is
pointless actually (sure "creator"-function can be exported from the
module only, but I'm talking about type-level solution).

I know that constraints (`... =>`) on data types are redundant/removed
from the language. And I'm not sure how it's possible to restrict that
parameter `a` (I know that it's possible to Java/C++/Perl6 (not sure),
some other languages but how to add such restriction in Haskell? IMHO
type families can help but I'm not sure how it will look (Sunny, Rainy
are "nullary" type, so...).

Is it possible for Haskell too?

===
Best regards, Paul
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Restrict type in phantom data-type

David McBride
This is maybe edging toward haskell-cafe territory, but you can
definitely do this in haskell.

{-# LANGUAGE DataKinds, KindSignatures #-}

data DayType = Sunny | Rainy

data Day (a :: DayType) = Day


sunnyDay :: Day Sunny
sunnyDay = Day

rainyDay :: Day Rainy
rainyDay = Day

-- impossibleDay :: Day ()
-- impossibleDay = Day

On Fri, Sep 1, 2017 at 10:18 AM, Baa <[hidden email]> wrote:

> Hello, List!
>
> For example, I have specialized (right nameis phantom?) type:
>
>   data Day a = Day { ... no `a` here }
>   data Sunny
>   data Rainy
>
>   joyToday :: Day Sunny -> IO ()
>   joyToday day = ...
>
>   melancholyToday :: Day Rainy -> IO ()
>   melancholyToday day = ...
>
> And I can create (in spite of that it's phantom) some day:
>
>   let day1 = Day {...} :: Day Sunny
>   joyToday day1
>
> but no problem to create `Day Int`, `Day Char`, etc which is
> pointless actually (sure "creator"-function can be exported from the
> module only, but I'm talking about type-level solution).
>
> I know that constraints (`... =>`) on data types are redundant/removed
> from the language. And I'm not sure how it's possible to restrict that
> parameter `a` (I know that it's possible to Java/C++/Perl6 (not sure),
> some other languages but how to add such restriction in Haskell? IMHO
> type families can help but I'm not sure how it will look (Sunny, Rainy
> are "nullary" type, so...).
>
> Is it possible for Haskell too?
>
> ===
> Best regards, Paul
> _______________________________________________
> Beginners mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Restrict type in phantom data-type

Francesco Ariis
In reply to this post by Baa
On Fri, Sep 01, 2017 at 05:18:02PM +0300, Baa wrote:

> Hello, List!
>
> For example, I have specialized (right nameis phantom?) type:
>
>   data Day a = Day { ... no `a` here }
>   data Sunny
>   data Rainy
>
>   joyToday :: Day Sunny -> IO ()
>   joyToday day = ...
>
>   melancholyToday :: Day Rainy -> IO ()
>   melancholyToday day = ...
>
> And I can create (in spite of that it's phantom) some day:
>
>   let day1 = Day {...} :: Day Sunny
>   joyToday day1

Hello Paul,

the usual way is create a module and export `smart` constructors:

    module MyType (rainy, Day, Sunny) -- *not* Day

    rainy :: Day Rainy
    rainy = undefined -- something here

That way you can use Day for time signatures but *not* `Day` the
constructor.

Does this solve your problem?
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Restrict type in phantom data-type

Francesco Ariis
On Fri, Sep 01, 2017 at 04:55:32PM +0200, Francesco Ariis wrote:
>     module MyType (rainy, Day, Sunny) -- *not* Day

I meant to write: -- not `Day(..)`
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Baa
Reply | Threaded
Open this post in threaded view
|

Re: Restrict type in phantom data-type

Baa
@Francesco: yes, it's a solution. But more interesting here is to make
it on type level, like we do it in D, Java, etc where you can say:
"class derived from...", "class before...", "class after...".


> On Fri, Sep 01, 2017 at 04:55:32PM +0200, Francesco Ariis wrote:
> >     module MyType (rainy, Day, Sunny) -- *not* Day  
>
> I meant to write: -- not `Day(..)`
> _______________________________________________
> Beginners mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners

_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Baa
Reply | Threaded
Open this post in threaded view
|

Re: Restrict type in phantom data-type

Baa
In reply to this post by Baa
I pereputal emails.
---

David, hello!

1. Is it the same/different as:

  data family Day a
  data Sunny
  data Rainy
  data instance Day Sunny = SunnyDay deriving Show
  data instance Day Rainy = RainyDay deriving Show

  ..and here you can not create `Day Int` object because no `Day Int`
  constructor (but you can create such constructor)

? Or in case with type families there is possibility to extend it to
`Day Int` and in case with DayaKinds it's totally impossible?

2. I read somewhere (on forums) that restrictions on data types... I
don't remember exactly, but something like they are not real
restrictions or are related to old extension which is/will be
deprecated. I'm not sure. Also, I'm not sure is it - in your example -
restriction (constraint) or something else. Am I wrong?

> This is maybe edging toward haskell-cafe territory, but you can
> definitely do this in haskell.
>
> {-# LANGUAGE DataKinds, KindSignatures #-}
>
> data DayType = Sunny | Rainy
>
> data Day (a :: DayType) = Day
>
>
> sunnyDay :: Day Sunny
> sunnyDay = Day
>
> rainyDay :: Day Rainy
> rainyDay = Day
>
> -- impossibleDay :: Day ()
> -- impossibleDay = Day
>
> On Fri, Sep 1, 2017 at 10:18 AM, Baa <[hidden email]> wrote:  
> > Hello, List!
> >
> > For example, I have specialized (right nameis phantom?) type:
> >
> >   data Day a = Day { ... no `a` here }
> >   data Sunny
> >   data Rainy
> >
> >   joyToday :: Day Sunny -> IO ()
> >   joyToday day = ...
> >
> >   melancholyToday :: Day Rainy -> IO ()
> >   melancholyToday day = ...
> >
> > And I can create (in spite of that it's phantom) some day:
> >
> >   let day1 = Day {...} :: Day Sunny
> >   joyToday day1
> >
> > but no problem to create `Day Int`, `Day Char`, etc which is
> > pointless actually (sure "creator"-function can be exported from the
> > module only, but I'm talking about type-level solution).
> >
> > I know that constraints (`... =>`) on data types are
> > redundant/removed from the language. And I'm not sure how it's
> > possible to restrict that parameter `a` (I know that it's possible
> > to Java/C++/Perl6 (not sure), some other languages but how to add
> > such restriction in Haskell? IMHO type families can help but I'm
> > not sure how it will look (Sunny, Rainy are "nullary" type, so...).
> >
> > Is it possible for Haskell too?
> >
> > ===
> > Best regards, Paul
> > _______________________________________________
> > Beginners mailing list
> > [hidden email]
> > http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners   
> _______________________________________________
> Beginners mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners 

_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Restrict type in phantom data-type

David McBride
The terminology for what you are looking for was phantom type.  That
is any type that looks like this, where the a is not mentioned on the
right hand side.

data Foo a = Foo

What happens with datakinds is when you write

data SomeType = Foo | Bar

By default there is a type SomeType and two values Foo and Bar, which
are of kind *, which is the default.  With datakinds enabled, it
creates two new types 'Foo, and 'Bar, which have a kind SomeType
(instead of *).  You can replace Rainy with 'Rainy in the other code I
gave.  It compiles either way because there is no other type Rainy, so
it assumes you must have meant 'Rainy.

As for type families, what you have there are called open type
families.  There is also a closed type families variant that prevents
more instances of the type family from being declared by the library
user.  It would look like this:

data Sunny
data Rainy

type family Night a where
  Night Sunny = SunnyNight
  Night Rainy = RainyNight

You could still write the following, which would not work in
datakinds, but at least there is no constructor that you could use
that would satisfy it other than the ones listed in the type family.

impossibleDay2 :: Day ()
impossibleDay2 = undefined

There may be more to this than I know, but I think that about covers it.

On Fri, Sep 1, 2017 at 11:23 AM, Baa <[hidden email]> wrote:

> I pereputal emails.
> ---
>
> David, hello!
>
> 1. Is it the same/different as:
>
>   data family Day a
>   data Sunny
>   data Rainy
>   data instance Day Sunny = SunnyDay deriving Show
>   data instance Day Rainy = RainyDay deriving Show
>
>   ..and here you can not create `Day Int` object because no `Day Int`
>   constructor (but you can create such constructor)
>
> ? Or in case with type families there is possibility to extend it to
> `Day Int` and in case with DayaKinds it's totally impossible?
>
> 2. I read somewhere (on forums) that restrictions on data types... I
> don't remember exactly, but something like they are not real
> restrictions or are related to old extension which is/will be
> deprecated. I'm not sure. Also, I'm not sure is it - in your example -
> restriction (constraint) or something else. Am I wrong?
>
>> This is maybe edging toward haskell-cafe territory, but you can
>> definitely do this in haskell.
>>
>> {-# LANGUAGE DataKinds, KindSignatures #-}
>>
>> data DayType = Sunny | Rainy
>>
>> data Day (a :: DayType) = Day
>>
>>
>> sunnyDay :: Day Sunny
>> sunnyDay = Day
>>
>> rainyDay :: Day Rainy
>> rainyDay = Day
>>
>> -- impossibleDay :: Day ()
>> -- impossibleDay = Day
>>
>> On Fri, Sep 1, 2017 at 10:18 AM, Baa <[hidden email]> wrote:
>> > Hello, List!
>> >
>> > For example, I have specialized (right nameis phantom?) type:
>> >
>> >   data Day a = Day { ... no `a` here }
>> >   data Sunny
>> >   data Rainy
>> >
>> >   joyToday :: Day Sunny -> IO ()
>> >   joyToday day = ...
>> >
>> >   melancholyToday :: Day Rainy -> IO ()
>> >   melancholyToday day = ...
>> >
>> > And I can create (in spite of that it's phantom) some day:
>> >
>> >   let day1 = Day {...} :: Day Sunny
>> >   joyToday day1
>> >
>> > but no problem to create `Day Int`, `Day Char`, etc which is
>> > pointless actually (sure "creator"-function can be exported from the
>> > module only, but I'm talking about type-level solution).
>> >
>> > I know that constraints (`... =>`) on data types are
>> > redundant/removed from the language. And I'm not sure how it's
>> > possible to restrict that parameter `a` (I know that it's possible
>> > to Java/C++/Perl6 (not sure), some other languages but how to add
>> > such restriction in Haskell? IMHO type families can help but I'm
>> > not sure how it will look (Sunny, Rainy are "nullary" type, so...).
>> >
>> > Is it possible for Haskell too?
>> >
>> > ===
>> > Best regards, Paul
>> > _______________________________________________
>> > Beginners mailing list
>> > [hidden email]
>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
>> _______________________________________________
>> Beginners mailing list
>> [hidden email]
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
>
> _______________________________________________
> Beginners mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Baa
Reply | Threaded
Open this post in threaded view
|

Re: Restrict type in phantom data-type

Baa
Thank you, David. It is a good seed, I'll read more about it, I used already GADTs and type families but I don't understand them so deep.
By the way, yes, I got warning about tick and when I added it (s/Rainy/'Rainy/) it fixed warning :)

2017-09-01 19:19 GMT+03:00 David McBride <[hidden email]>:
The terminology for what you are looking for was phantom type.  That
is any type that looks like this, where the a is not mentioned on the
right hand side.

data Foo a = Foo

What happens with datakinds is when you write

data SomeType = Foo | Bar

By default there is a type SomeType and two values Foo and Bar, which
are of kind *, which is the default.  With datakinds enabled, it
creates two new types 'Foo, and 'Bar, which have a kind SomeType
(instead of *).  You can replace Rainy with 'Rainy in the other code I
gave.  It compiles either way because there is no other type Rainy, so
it assumes you must have meant 'Rainy.

As for type families, what you have there are called open type
families.  There is also a closed type families variant that prevents
more instances of the type family from being declared by the library
user.  It would look like this:

data Sunny
data Rainy

type family Night a where
  Night Sunny = SunnyNight
  Night Rainy = RainyNight

You could still write the following, which would not work in
datakinds, but at least there is no constructor that you could use
that would satisfy it other than the ones listed in the type family.

impossibleDay2 :: Day ()
impossibleDay2 = undefined

There may be more to this than I know, but I think that about covers it.

On Fri, Sep 1, 2017 at 11:23 AM, Baa <[hidden email]> wrote:
> I pereputal emails.
> ---
>
> David, hello!
>
> 1. Is it the same/different as:
>
>   data family Day a
>   data Sunny
>   data Rainy
>   data instance Day Sunny = SunnyDay deriving Show
>   data instance Day Rainy = RainyDay deriving Show
>
>   ..and here you can not create `Day Int` object because no `Day Int`
>   constructor (but you can create such constructor)
>
> ? Or in case with type families there is possibility to extend it to
> `Day Int` and in case with DayaKinds it's totally impossible?
>
> 2. I read somewhere (on forums) that restrictions on data types... I
> don't remember exactly, but something like they are not real
> restrictions or are related to old extension which is/will be
> deprecated. I'm not sure. Also, I'm not sure is it - in your example -
> restriction (constraint) or something else. Am I wrong?
>
>> This is maybe edging toward haskell-cafe territory, but you can
>> definitely do this in haskell.
>>
>> {-# LANGUAGE DataKinds, KindSignatures #-}
>>
>> data DayType = Sunny | Rainy
>>
>> data Day (a :: DayType) = Day
>>
>>
>> sunnyDay :: Day Sunny
>> sunnyDay = Day
>>
>> rainyDay :: Day Rainy
>> rainyDay = Day
>>
>> -- impossibleDay :: Day ()
>> -- impossibleDay = Day
>>
>> On Fri, Sep 1, 2017 at 10:18 AM, Baa <[hidden email]> wrote:
>> > Hello, List!
>> >
>> > For example, I have specialized (right nameis phantom?) type:
>> >
>> >   data Day a = Day { ... no `a` here }
>> >   data Sunny
>> >   data Rainy
>> >
>> >   joyToday :: Day Sunny -> IO ()
>> >   joyToday day = ...
>> >
>> >   melancholyToday :: Day Rainy -> IO ()
>> >   melancholyToday day = ...
>> >
>> > And I can create (in spite of that it's phantom) some day:
>> >
>> >   let day1 = Day {...} :: Day Sunny
>> >   joyToday day1
>> >
>> > but no problem to create `Day Int`, `Day Char`, etc which is
>> > pointless actually (sure "creator"-function can be exported from the
>> > module only, but I'm talking about type-level solution).
>> >
>> > I know that constraints (`... =>`) on data types are
>> > redundant/removed from the language. And I'm not sure how it's
>> > possible to restrict that parameter `a` (I know that it's possible
>> > to Java/C++/Perl6 (not sure), some other languages but how to add
>> > such restriction in Haskell? IMHO type families can help but I'm
>> > not sure how it will look (Sunny, Rainy are "nullary" type, so...).
>> >
>> > Is it possible for Haskell too?
>> >
>> > ===
>> > Best regards, Paul
>> > _______________________________________________
>> > Beginners mailing list
>> > [hidden email]
>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
>> _______________________________________________
>> Beginners mailing list
>> [hidden email]
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
>
> _______________________________________________
> Beginners mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners


_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners