summaryrefslogtreecommitdiff
path: root/docs/users_guide/exts/derive_any_class.rst
blob: 4cd241d9b0d633eb95d37bafca57bd4d757f8e0d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
.. _derive-any-class:

Deriving any other class
------------------------

.. extension:: DeriveAnyClass
    :shortdesc: Enable deriving for any class.

    :since: 7.10.1

    Allow use of any typeclass in ``deriving`` clauses.

With :extension:`DeriveAnyClass` you can derive any other class. The compiler
will simply generate an instance declaration with no explicitly-defined
methods.
This is
mostly useful in classes whose `minimal set <#minimal-pragma>`__ is
empty, and especially when writing
`generic functions <#generic-programming>`__.

As an example, consider a simple pretty-printer class ``SPretty``, which outputs
pretty strings: ::

    {-# LANGUAGE DefaultSignatures, DeriveAnyClass #-}

    class SPretty a where
      sPpr :: a -> String
      default sPpr :: Show a => a -> String
      sPpr = show

If a user does not provide a manual implementation for ``sPpr``, then it will
default to ``show``. Now we can leverage the :extension:`DeriveAnyClass` extension to
easily implement a ``SPretty`` instance for a new data type: ::

    data Foo = Foo deriving (Show, SPretty)

The above code is equivalent to: ::

    data Foo = Foo deriving Show
    instance SPretty Foo

That is, an ``SPretty Foo`` instance will be created with empty implementations
for all methods. Since we are using :extension:`DefaultSignatures` in this example, a
default implementation of ``sPpr`` is filled in automatically.

Note the following details

- In case you try to derive some
  class on a newtype, and :extension:`GeneralizedNewtypeDeriving` is also on,
  :extension:`DeriveAnyClass` takes precedence.

- The instance context is determined by the type signatures of the derived
  class's methods. For instance, if the class is: ::

    class Foo a where
      bar :: a -> String
      default bar :: Show a => a -> String
      bar = show

      baz :: a -> a -> Bool
      default baz :: Ord a => a -> a -> Bool
      baz x y = compare x y == EQ

  And you attempt to derive it using :extension:`DeriveAnyClass`: ::

    instance Eq   a => Eq   (Option a) where ...
    instance Ord  a => Ord  (Option a) where ...
    instance Show a => Show (Option a) where ...

    data Option a = None | Some a deriving Foo

  Then the derived ``Foo`` instance will be: ::

    instance (Show a, Ord a) => Foo (Option a)

  Since the default type signatures for ``bar`` and ``baz`` require ``Show a``
  and ``Ord a`` constraints, respectively.

  Constraints on the non-default type signatures can play a role in inferring
  the instance context as well. For example, if you have this class: ::

    class HigherEq f where
      (==#) :: f a -> f a -> Bool
      default (==#) :: Eq (f a) => f a -> f a -> Bool
      x ==# y = (x == y)

  And you tried to derive an instance for it: ::

    instance Eq a => Eq (Option a) where ...
    data Option a = None | Some a deriving HigherEq

  Then it will fail with an error to the effect of: ::

    No instance for (Eq a)
        arising from the 'deriving' clause of a data type declaration

  That is because we require an ``Eq (Option a)`` instance from the default
  type signature for ``(==#)``, which in turn requires an ``Eq a`` instance,
  which we don't have in scope. But if you tweak the definition of
  ``HigherEq`` slightly: ::

    class HigherEq f where
      (==#) :: Eq a => f a -> f a -> Bool
      default (==#) :: Eq (f a) => f a -> f a -> Bool
      x ==# y = (x == y)

  Then it becomes possible to derive a ``HigherEq Option`` instance. Note that
  the only difference is that now the non-default type signature for ``(==#)``
  brings in an ``Eq a`` constraint. Constraints from non-default type
  signatures never appear in the derived instance context itself, but they can
  be used to discharge obligations that are demanded by the default type
  signatures. In the example above, the default type signature demanded an
  ``Eq a`` instance, and the non-default signature was able to satisfy that
  request, so the derived instance is simply: ::

    instance HigherEq Option

- :extension:`DeriveAnyClass` can be used with partially applied classes,
  such as ::

    data T a = MKT a deriving( D Int )

  which generates ::

    instance D Int a => D Int (T a) where {}

- :extension:`DeriveAnyClass` can be used to fill in default instances for
  associated type families: ::

    {-# LANGUAGE DeriveAnyClass, TypeFamilies #-}

    class Sizable a where
      type Size a
      type Size a = Int

    data Bar = Bar deriving Sizable

    doubleBarSize :: Size Bar -> Size Bar
    doubleBarSize s = 2*s

  The ``deriving( Sizable )`` is equivalent to saying ::

    instance Sizeable Bar where {}

  and then the normal rules for filling in associated types from the
  default will apply, making ``Size Bar`` equal to ``Int``.