Well, it seems to be exactly like type classes. What if instead of implementing 
this "roles" we simply add a type class, say, "HasRepresentationalArgument", 
which can be (and is) derived automatically. Of course, multiple arguments 
could be a problem, but, since we already have polymorphic kinds, not a big one.

Отправлено с iPad

> 08 окт. 2013 г., в 0:16, Richard Eisenberg <e...@cis.upenn.edu> написал(а):
> 
> You raise an excellent point, and yes, your understanding of how roles work 
> in this case is correct.
> 
> The problem with your proposal is that it's rather involved to implement and 
> maintain -- essentially, every type and type variable would need to be 
> annotated with both a role and a kind. (These annotations would generally be 
> invisible to users, but quite apparent to implementors.) The current solution 
> is admittedly incomplete in this area, but it requires tracking roles only 
> for parameters to datatypes and classes. We're waiting to see how important 
> this particular issue is in practice before committing to implementing it (a 
> medium-sized project) and maintaining it into perpetuity.
> 
> Richard
> 
>> On Oct 7, 2013, at 3:55 PM, migmit wrote:
>> 
>> Something bugs me here.
>> 
>> If some type variable a is used as a parameter to another type variable t, 
>> then it's considered nominal. I suppose, that's because it is possible that 
>> it would be nominal for some specific t. But we might just know that in our 
>> application it's always representational, for every possible t that we would 
>> ever use. In this case, we might want to a) explicitly state that t's type 
>> parameter should always be representational, and b) at the same time make a 
>> representational. Seems like a probable scenario to me.
>> 
>> Отправлено с iPad
>> 
>>> 07 окт. 2013 г., в 17:26, Richard Eisenberg <e...@cis.upenn.edu> написал(а):
>>> 
>>> As you may have heard, /roles/ will be introduced with GHC 7.8. Roles are a 
>>> mechanism to allow for safe 0-cost conversions between newtypes and their 
>>> base types. GeneralizedNewtypeDeriving (GND) already did this for class 
>>> instances, but in an unsafe way -- the feature has essentially been 
>>> retrofitted to work with roles. This means that some uses of GND that 
>>> appear to be unsafe will no longer work. See the wiki page [1] or slides 
>>> from a recent presentation [2] for more info.
>>> 
>>> [1] : http://ghc.haskell.org/trac/ghc/wiki/Roles
>>> [2] : http://www.cis.upenn.edu/~eir/papers/2013/roles/roles-slides.pdf
>>> 
>>> I am writing because it's unclear what the *default* role should be -- that 
>>> is, should GND be allowed by default? Examples follow, but the critical 
>>> issue is this:
>>> 
>>> * If we allow GND by default anywhere it is type-safe, datatypes (even 
>>> those that don't export constructors) will not be abstract by default. 
>>> Library writers would have to use a role annotation everywhere they wish to 
>>> declare a datatype they do not want users to be able to inspect. (Roles 
>>> still keep type-*un*safe GND from happening.)
>>> 
>>> * If we disallow GND by default, then perhaps lots of current uses of GND 
>>> will break. Library writers will have to explicitly declare when they wish 
>>> to permit GND involving a datatype.
>>> 
>>> Which do we think is better?
>>> 
>>> Examples: The chief example demonstrating the problem is (a hypothetical 
>>> implementation of) Set:
>>> 
>>> > module Set (Set) where   -- note: no constructors exported!
>>> >
>>> > data Set a = MkSet [a]
>>> > insert :: Ord a => a -> Set a -> Set a
>>> > ...
>>> 
>>> > {-# LANGUAGE GeneralizedNewtypeDeriving, StandaloneDeriving #-}
>>> > module Client where
>>> >
>>> > import Set
>>> >
>>> > newtype Age = MkAge Int deriving Eq
>>> >
>>> > instance Ord Age where
>>> >   (MkAge a) `compare` (MkAge b) = b `compare` a   -- flip operands, 
>>> > reversing the order
>>> >
>>> > class HasSet a where
>>> >   getSet :: Set a
>>> >
>>> > instance HasSet Int where
>>> >   getSet = insert 2 (insert 5 empty)
>>> >
>>> > deriving instance HasSet Age
>>> >
>>> > good :: Set Int
>>> > good = getSet
>>> >
>>> > bad :: Set Age
>>> > bad = getSet
>>> 
>>> According to the way GND works, `good` and `bad` will have the same runtime 
>>> representation. But, using Set operations on `bad` would indeed be bad -- 
>>> because the Ord instance for Age is different than that for Int, Set 
>>> operations will fail unexpectedly on `bad`. The problem is that Set should 
>>> really be abstract, but we've been able to break this abstraction with GND. 
>>> Note that there is no type error in these operations, just wrong behavior.
>>> 
>>> So, if we default to *no* GND, then the "deriving" line above would have an 
>>> error and this problem wouldn't happen. If we default to *allowing* GND, 
>>> then the writer of Set would have to include
>>> > type role Set nominal
>>> in the definition of the Set module to prevent the use of GND. (Why that 
>>> peculiar annotation? See the linked further reading, above.)
>>> 
>>> Although it doesn't figure in this example, a library writer who wishes to 
>>> allow GND in the default-no scenario would need a similar annotation
>>> > type role Foo representational
>>> to allow it.
>>> 
>>> There are clearly reasons for and against either decision, but which is 
>>> better? Let the users decide!
>>> 
>>> Discussion time: 2 weeks.
>>> 
>>> Thanks!
>>> Richard
>>> _______________________________________________
>>> Glasgow-haskell-users mailing list
>>> Glasgow-haskell-users@haskell.org
>>> http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
> 
_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

Reply via email to