Re: coercing newtypes

2000-04-23 Thread Marcin 'Qrczak' Kowalczyk

Wed, 19 Apr 2000 03:29:44 -0700, Simon Peyton-Jones [EMAIL PROTECTED] pisze:

 There is also the question of whether newtype is a good thing at all.
 Maybe we'd be better off with Gofer's restricted type synonyms.

I prefer newtypes, because (1) IMHO the rules are simpler, (2) newtype
is often needed anyway for making instances, (3) the knowledge of
the representation can be distributed across modules as for datatypes.

-- 
 __("Marcin Kowalczyk * [EMAIL PROTECTED] http://qrczak.ids.net.pl/
 \__/  GCS/M d- s+:-- a23 C+++$ UL++$ P+++ L++$ E-
  ^^  W++ N+++ o? K? w(---) O? M- V? PS-- PE++ Y? PGP+ t
QRCZAK  5? X- R tv-- b+++ DI D- G+ e h! r--%++ y-





Deriving for newtypes (Re: coercing newtypes)

2000-04-23 Thread Marcin 'Qrczak' Kowalczyk

Mon, 17 Apr 2000 10:07:51 -0400, Chris Okasaki [EMAIL PROTECTED] pisze:

 Many of you have run across the problem with newtypes that, although
 it is very cheap to coerce between the newtype and the base type, it
 can be very expensive to coerce between, say, a list of the newtype
 and a list of the base type. Stephanie Weirich and I are working
 on a proposal for the Haskell Workshop addressing this problem,
 and we would welcome any feedback from the community.

Fo me it looks like it requires introducing more special rules to
the language than it's worth it. I don't think that the problem of
converting complex structures of newtypes is so common to justify
introducing not so pretty rules to the language.

GHC has the RULES pragma and unsafeCoerce#, which can be used in a
particular case when the performance is so critical and the compiler
is unable to optimize the conversion itself.



Instead, I think that the following extension would be more useful.

When we use newtype to create a new numeric type, we must make
instances of various classes ourselves. The deriving mechamism saves
us from boring Eq and Ord instances, but will not help with Num or
Integral even if they are "obvious".

Proposal. Allow specifying any single-parameter type class in the
deriving list of a newtype, provided that method types agree with
the following rules, the type under the newtype is an instance of
that class, and the newtype is an instance of all superclasses.

Each method is derived from the corresponding method for the oldtype.
Implementation is easier than specification of exact rules :-)
The intent is that the same physical code will work for the newtype
as well. To obtain this, the implementation of the method is formally
converted, as driven by old and new types of the method.

An expression e of type t is converted to C[e] thus:

- If t does not mention the oldtype, the target type is the same and
  C[e] = e.

- If t is the oldtype, then C[e] = N e, where N is the newtype's
  constructor.

- If t is a function type, then C[e] = e `seq` \x - C[e (C'[x])],
  where C' is the dual conversion, from the new type to the old type.

- If t is a tuple type, then
  C[e] = case e of (e1,...,eN) - (C[e1],...,C[eN]).
  This is needed e.g. for Integral's quotRem.

- If t is the list type, then C[e] = map (\x - C[x]) e.
  This is needed e.g. for Enum's enumFromTo.

- Otherwise the class is not derivable.

So it works for all Prelude type classes. The only conflict with
current derivings is for Show and Read, which is unfortunate because
it's not obvious which case is needed and I'm not sure how to
resolve it.

-- 
 __("Marcin Kowalczyk * [EMAIL PROTECTED] http://qrczak.ids.net.pl/
 \__/  GCS/M d- s+:-- a23 C+++$ UL++$ P+++ L++$ E-
  ^^  W++ N+++ o? K? w(---) O? M- V? PS-- PE++ Y? PGP+ t
QRCZAK  5? X- R tv-- b+++ DI D- G+ e h! r--%++ y-





RE: coercing newtypes

2000-04-19 Thread Simon Peyton-Jones

| Many of you have run across the problem with
| newtypes that, although it is very cheap to
| coerce between the newtype and the base type, it
| can be very expensive to coerce between, say,
| a list of the newtype and a list of the base type.
| Stephanie Weirich and I are working on a proposal
| for the Haskell Workshop addressing this problem,
| and we would welcome any feedback from the community.

Thanks for the draft, which I read last night.  Interesting.
I have two main comments.

1.  Personally, I've never actually been bitten by this problem.
Have you?   In other words, how practically important is it?
(Regardless, it's a wart, I must agree.)

2.  More substantially, you describe your solution as lightweight,
but it involves quite a bit: multi-param type classes, automatic
derivings..  And STILL the programmer has to fiddle about with
frankly non-obvious constructions (Section 4).   So I have an
alternative suggestion: provide 'cast' in the language.

That is, if e :: t
then(cast e) :: s

   for any type s that has the same representation as t. 

So I need to add some rules saying what it means to 'have the
same representation' but that's pretty easy.  And there's no problem
with nested types.

What made me think about this is that GHC internally has exactly such
a thing (it's called 'coerce' rather than 'cast').   Newtype constructors
are compiled into applications of 'coerce', and similarly pattern matching.
It seems bizarre to require the *programmer* to write complicated code
(like (Apl . f . unApl)) in order to get the *compiler* to produce the very
simple code (cast t).   That's back to front!


One could also deal with the abstraction issue: you can say
that two types have the same representation iff you could convert
a value of one type into a value of the other, *using the constructors
currently in scope*.   So if the ADT doesn't expose the constructors
you can't cast.


There is also the question of whether newtype is a good thing at all.
Maybe we'd be better off with Gofer's restricted type synonyms.

Simon