Automatically deriving Generic for every algebraic data type

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

Automatically deriving Generic for every algebraic data type

Wolfgang Jeltsch-2
Hi,

if you do generic programming these days, you can use DeriveAnyClass to
write code like the following (where Serializable is a class with a
generic default implementation):

> data Tree a = Leaf | Branch (Tree a) a (Tree a)
>               deriving (Generic, Serializable)

It would be great, if you could just write the following instead:

> data Tree a = Leaf | Branch (Tree a) a (Tree a) deriving Serializable

This would correspond exactly to what you do when using standard Haskell
deriving. It could be made possible by letting the compiler instantiate
the Generic class automatically every time an algebraic data type is
declared. A potential downside of this would be that programmers would
not be able to define non-standard instances of Generics, but I actually
cannot see that this is very useful anyhow.

Any comments?

All the best,
Wolfgang

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

Re: Automatically deriving Generic for every algebraic data type

Wolfgang Jeltsch-2

Am Donnerstag, den 04.02.2016, 14:19 +0200 schrieb Wolfgang Jeltsch:

> Hi,
>
> if you do generic programming these days, you can use DeriveAnyClass to
> write code like the following (where Serializable is a class with a
> generic default implementation):
>
> > data Tree a = Leaf | Branch (Tree a) a (Tree a)
> >               deriving (Generic, Serializable)
>
> It would be great, if you could just write the following instead:
>
> > data Tree a = Leaf | Branch (Tree a) a (Tree a) deriving Serializable
>
> This would correspond exactly to what you do when using standard Haskell
> deriving. It could be made possible by letting the compiler instantiate
> the Generic class automatically every time an algebraic data type is
> declared. A potential downside of this would be that programmers would
> not be able to define non-standard instances of Generics, but I actually
> cannot see that this is very useful anyhow.

I want to add that this would probably allow us to implement all the
other deriving mechanisms (for standard classes, for Functor, etc.)
entirely in libraries, using generic programming, without forcing users
to change their code by adding deriving of Generic. Maybe a future
standard Haskell would not even have deriving rules hardwired into the
language anymore (which always felt somehow wrong to me). Wouldn’t this
be great? ;-)

All the best,
Wolfgang


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

Re: Automatically deriving Generic for every algebraic data type

Oleg Grenrus
Hi,

sometimes I want to use Generic derivation, but don’t want expose the Generic
instance outside the module.  The reason, is that for some types I want to
export only smart constructors / modifier lenses; yet the structure is probably
simple enough to benefit from `Generic`.

If it will be possible to restrict export of the Generic instance, then I don’t
see problem of auto-deriving it for everything possible though.

- Oleg

On 04 Feb 2016, at 14:28, Wolfgang Jeltsch <[hidden email]> wrote:


Am Donnerstag, den 04.02.2016, 14:19 +0200 schrieb Wolfgang Jeltsch:
Hi,

if you do generic programming these days, you can use DeriveAnyClass to
write code like the following (where Serializable is a class with a
generic default implementation):

data Tree a = Leaf | Branch (Tree a) a (Tree a)
             deriving (Generic, Serializable)

It would be great, if you could just write the following instead:

data Tree a = Leaf | Branch (Tree a) a (Tree a) deriving Serializable

This would correspond exactly to what you do when using standard Haskell
deriving. It could be made possible by letting the compiler instantiate
the Generic class automatically every time an algebraic data type is
declared. A potential downside of this would be that programmers would
not be able to define non-standard instances of Generics, but I actually
cannot see that this is very useful anyhow.

I want to add that this would probably allow us to implement all the
other deriving mechanisms (for standard classes, for Functor, etc.)
entirely in libraries, using generic programming, without forcing users
to change their code by adding deriving of Generic. Maybe a future
standard Haskell would not even have deriving rules hardwired into the
language anymore (which always felt somehow wrong to me). Wouldn’t this
be great? ;-) 

All the best,
Wolfgang


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


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

signature.asc (859 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Automatically deriving Generic for every algebraic data type

Ryan Scott
In reply to this post by Wolfgang Jeltsch-2
I'm a pretty solid -1 on this idea.

On a general level, I'm opposed to the idea of deriving typeclasses
without the programmer opting in. Most typeclasses express operations
that your datatype must support, and in the case of Generic(1), it
mandates that users can convert between values of your datatype and an
isomorphic representation type. As Oleg noted, this completely
destroys encapsulation for datatypes whose constructors you don't want
to export.

Another issue is the nontrivial cost of automatic derivation.
Typeclasses can be surprisingly expensive to derive. About a year ago,
Reid Barton measured the amount of increase in code size that each
derivable typeclass contributes [1], and Generic was far and away the
most expensive one. There's also the issue that deriving Generic on
large datatypes can drastically increase the amount of memory needed
during compilation [2].

Yet another problem is that deriving Generic1 simply doesn't work for
every datatype. Not only does deriving Generic1 not work with
sophisticated language features (e.g., -XExistentialQuantification
[3]) by design, but there are still a number of outstanding bugs that
prevent legitimate Generic1 from being deriving automatically. For
example, the following datatype:

  newtype Compose (f :: k1 -> *) (g :: k2 -> k1) (a :: k2) = Compose (f (g a))

chokes when attempting to derive Generic1 automatically [4]. You have
to hack around this by using -XStandaloneDeriving with a
programmer-specified instance context.

One could imagine a compromise in which Generic(1) would not be
derived for datatypes for which attempting to derive those classes
yields an error. But I would argue that this is very undesirable,
since programmers would just expect every datatype to work out of the
box with Generic(1), only to find "Cannot find instance Generic1
Compose"-like errors when they try using Generic1 operations on
datatypes that trip the bug mentioned in [4].

There are exceptions to the don't-derive-typeclasses-automatically
rule, with Typeable being a notable example [5]. But deriving Typeable
has the benefit that (1) it doesn't impose many requirements on your
datatype (other than you can get a TypeRep for it), (2) it's cheap to
derive (see the table in [1]), and (3) it works on literally every
datatype.

Ryan S.
-----
[1] https://ghc.haskell.org/trac/ghc/ticket/9557#comment:8
[2] https://ghc.haskell.org/trac/ghc/ticket/5642
[3] https://ghc.haskell.org/trac/ghc/ticket/10514
[4] https://ghc.haskell.org/trac/ghc/ticket/10524#comment:16
[5] https://ghc.haskell.org/trac/ghc/ticket/8950
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Automatically deriving Generic for every algebraic data type

Roman Cheplyaka-2
In reply to this post by Wolfgang Jeltsch-2
On 02/04/2016 02:19 PM, Wolfgang Jeltsch wrote:

> Hi,
>
> if you do generic programming these days, you can use DeriveAnyClass to
> write code like the following (where Serializable is a class with a
> generic default implementation):
>
>> data Tree a = Leaf | Branch (Tree a) a (Tree a)
>>               deriving (Generic, Serializable)
>
> It would be great, if you could just write the following instead:
>
>> data Tree a = Leaf | Branch (Tree a) a (Tree a) deriving Serializable
>
> This would correspond exactly to what you do when using standard Haskell
> deriving. It could be made possible by letting the compiler instantiate
> the Generic class automatically every time an algebraic data type is
> declared. A potential downside of this would be that programmers would
> not be able to define non-standard instances of Generics, but I actually
> cannot see that this is very useful anyhow.
>
> Any comments?
GHC.Generics already have an unfair advantage over the alternative (and
arguably, superior) libraries, such as generics-sop. I wouldn't want to
give it even more special treatment than it receives right now.

Roman


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

signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Automatically deriving Generic for every algebraic data type

Andres Löh-3
In reply to this post by Ryan Scott
I agree with Ryan on this, i.e., a general automatic DeriveGeneric
would not be a good idea right now. Note also that it is already the
case that if you want to derive certain classes, you may have to
derive other classes as well, namely if superclasses are involved. So
you cannot say "deriving Ord", but rather have to say "deriving (Eq,
Ord)". In this sense, I don't think the situation with "Serialize" is
that much worse.

An AutoDeriveGeneric language extension that can be enabled for
particular modules might be a possible compromise I could live with.

I think it is worth thinking more generally about a replacement for
"deriving" that has the chance of making different approaches feel
more similar. I'm not overly happy with the current situation wrt
DeriveAnyClass and the way conflicts between built-in, newtype- and
anyclass-deriving are resolved.

Cheers,
  Andres



On Thu, Feb 4, 2016 at 3:20 PM, Ryan Scott <[hidden email]> wrote:

> I'm a pretty solid -1 on this idea.
>
> On a general level, I'm opposed to the idea of deriving typeclasses
> without the programmer opting in. Most typeclasses express operations
> that your datatype must support, and in the case of Generic(1), it
> mandates that users can convert between values of your datatype and an
> isomorphic representation type. As Oleg noted, this completely
> destroys encapsulation for datatypes whose constructors you don't want
> to export.
>
> Another issue is the nontrivial cost of automatic derivation.
> Typeclasses can be surprisingly expensive to derive. About a year ago,
> Reid Barton measured the amount of increase in code size that each
> derivable typeclass contributes [1], and Generic was far and away the
> most expensive one. There's also the issue that deriving Generic on
> large datatypes can drastically increase the amount of memory needed
> during compilation [2].
>
> Yet another problem is that deriving Generic1 simply doesn't work for
> every datatype. Not only does deriving Generic1 not work with
> sophisticated language features (e.g., -XExistentialQuantification
> [3]) by design, but there are still a number of outstanding bugs that
> prevent legitimate Generic1 from being deriving automatically. For
> example, the following datatype:
>
>   newtype Compose (f :: k1 -> *) (g :: k2 -> k1) (a :: k2) = Compose (f (g a))
>
> chokes when attempting to derive Generic1 automatically [4]. You have
> to hack around this by using -XStandaloneDeriving with a
> programmer-specified instance context.
>
> One could imagine a compromise in which Generic(1) would not be
> derived for datatypes for which attempting to derive those classes
> yields an error. But I would argue that this is very undesirable,
> since programmers would just expect every datatype to work out of the
> box with Generic(1), only to find "Cannot find instance Generic1
> Compose"-like errors when they try using Generic1 operations on
> datatypes that trip the bug mentioned in [4].
>
> There are exceptions to the don't-derive-typeclasses-automatically
> rule, with Typeable being a notable example [5]. But deriving Typeable
> has the benefit that (1) it doesn't impose many requirements on your
> datatype (other than you can get a TypeRep for it), (2) it's cheap to
> derive (see the table in [1]), and (3) it works on literally every
> datatype.
>
> Ryan S.
> -----
> [1] https://ghc.haskell.org/trac/ghc/ticket/9557#comment:8
> [2] https://ghc.haskell.org/trac/ghc/ticket/5642
> [3] https://ghc.haskell.org/trac/ghc/ticket/10514
> [4] https://ghc.haskell.org/trac/ghc/ticket/10524#comment:16
> [5] https://ghc.haskell.org/trac/ghc/ticket/8950
> _______________________________________________
> ghc-devs mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs