
Hello,
The general functionality for this seems useful, but we should be careful
exactly what types we allow in the 'newtype wrap/unwrap' declarations. For
example, would we allow something like this:
newtype wrap cvt :: f a -> f (Dual a)
If we just worry about what's in scope, then it should be accepted, however
this function could still be used to break the invariant on `Set` because
it is polymorphic.
In general, I was never comfortable with GHC's choice to add an axiom
equating a newtype and its representation type, because it looks unsound to
me (without any type-functions or newtype deriving).
For example, consider:
newtype T a = MkT Int
Now, if this generates an axiom asserting that `froall a. T a ~ Int`, then
we can derive a contradiction:
T Int ~ Int ~ T Char, and hence `Int ~ Char`.
It looks like what we need is a different concept: one that talks about the
equality of the representations of types, rather then equality of the types
themselves.
-Iavor
On Mon, Jan 14, 2013 at 10:09 AM, Simon Peyton-Jones
Friends****
** **
I’d like to propose a way to “promote” newtypes over their enclosing type. Here’s the writeup****
http://hackage.haskell.org/trac/ghc/wiki/NewtypeWrappers****
** **
Any comments? Below is the problem statement, taken from the above page.* ***
** **
I’d appreciate****
**· **A sense of whether you care. Does this matter?****
**· **Improvements to the design I propose****
** **
Simon****
** **
** **
** **
*The problem*
Suppose we have ****
newtype Age = MkAge Int****
Then if n :: Int, we can convert n to an Age thus: MkAge n :: Age. Moreover, this conversion is a type conversion only, and involves no runtime instructions whatsoever. This cost model -- that newtypes are free -- is important to Haskell programmers, and encourages them to use newtypes freely to express type distinctions without introducing runtime overhead. ****
Alas, the newtype cost model breaks down when we involve other data structures. Suppose we have these declarations ****
data T a = TLeaf a | TNode (Tree a) (Tree a)****
data S m a = SLeaf (m a) | SNode (S m a) (S m a)****
and we have these variables in scope ****
x1 :: [Int]****
x2 :: Char -> Int****
x3 :: T Int****
x4 :: S IO Int****
Can we convert these into the corresponding forms where the Int is replaced by Age? Alas, not easily, and certainly not without overhead. *** *
- For x1 we can write map MkAge x1 :: [Age]. But this does not follow the newtype cost model: there will be runtime overhead from executing the map at runtime, and sharing will be lost too. Could GHC optimise the map somehow? This is hard; apart from anything else, how would GHC know that map was special? And it it gets worse. ****
- For x2 we'd have to eta-expand: (\y -> MkAge (x2 y)) :: Char -> Age. But this isn't good either, because eta exapansion isn't semantically valid (if x2 was bottom, seq could distinguish the two). See #7542http://hackage.haskell.org/trac/ghc/ticket/7542for a real life example. ****
- For x3, we'd have to map over T, thus mapT MkAge x3. But what if mapTdidn't exist? We'd have to make it. And not all data types have maps. S is a harder one: you could only map over S-values if m was a functor. There's a lot of discussion abou this on #2110http://hackage.haskell.org/trac/ghc/ticket/2110. ****
** **
_______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users