summaryrefslogtreecommitdiff
path: root/docs/users_guide/exts/newtype_deriving.rst
blob: 8856287a916015ffaf63deeab0f8ffd0380418c6 (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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
.. _newtype-deriving:

Generalised derived instances for newtypes
------------------------------------------

.. extension:: GeneralisedNewtypeDeriving
               GeneralizedNewtypeDeriving
    :shortdesc: Enable newtype deriving.

    :since: 6.8.1. British spelling since 8.6.1.

    :status: Included in :extension:`GHC2021`

    Enable GHC's cunning generalised deriving mechanism for ``newtype``\s

When you define an abstract type using ``newtype``, you may want the new
type to inherit some instances from its representation. In Haskell 98,
you can inherit instances of ``Eq``, ``Ord``, ``Enum`` and ``Bounded``
by deriving them, but for any other classes you have to write an
explicit instance declaration. For example, if you define ::

      newtype Dollars = Dollars Int

and you want to use arithmetic on ``Dollars``, you have to explicitly
define an instance of ``Num``: ::

      instance Num Dollars where
        Dollars a + Dollars b = Dollars (a+b)
        ...

All the instance does is apply and remove the ``newtype`` constructor.
It is particularly galling that, since the constructor doesn't appear at
run-time, this instance declaration defines a dictionary which is
*wholly equivalent* to the ``Int`` dictionary, only slower!

:extension:`DerivingVia` (see :ref:`deriving-via`) is a generalization of
this idea.

.. _generalized-newtype-deriving:

Generalising the deriving clause
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

GHC now permits such instances to be derived instead, using the extension
:extension:`GeneralizedNewtypeDeriving`, so one can write ::

      newtype Dollars = Dollars { getDollars :: Int } deriving (Eq,Show,Num)

and the implementation uses the *same* ``Num`` dictionary for
``Dollars`` as for ``Int``. In other words, GHC will generate something that
resembles the following code ::

      instance Num Int => Num Dollars

and then attempt to simplify the ``Num Int`` context as much as possible.
GHC knows that there is a ``Num Int`` instance in scope, so it is able to
discharge the ``Num Int`` constraint, leaving the code that GHC actually
generates ::

      instance Num Dollars

One can think of this instance being implemented with the same code as the
``Num Int`` instance, but with ``Dollars`` and ``getDollars`` added wherever
necessary in order to make it typecheck. (In practice, GHC uses a somewhat
different approach to code generation. See the :ref:`precise-gnd-specification`
section below for more details.)

We can also derive instances of constructor classes in a similar way.
For example, suppose we have implemented state and failure monad
transformers, such that ::

      instance Monad m => Monad (State s m)
      instance Monad m => Monad (Failure m)

In Haskell 98, we can define a parsing monad by ::

      type Parser tok m a = State [tok] (Failure m) a

which is automatically a monad thanks to the instance declarations
above. With the extension, we can make the parser type abstract, without
needing to write an instance of class ``Monad``, via ::

      newtype Parser tok m a = Parser (State [tok] (Failure m) a)
                             deriving Monad

In this case the derived instance declaration is of the form ::

      instance Monad (State [tok] (Failure m)) => Monad (Parser tok m)

Notice that, since ``Monad`` is a constructor class, the instance is a
*partial application* of the newtype, not the entire left hand side. We
can imagine that the type declaration is "eta-converted" to generate the
context of the instance declaration.

We can even derive instances of multi-parameter classes, provided the
newtype is the last class parameter. In this case, a "partial
application" of the class appears in the ``deriving`` clause. For
example, given the class ::

      class StateMonad s m | m -> s where ...
      instance Monad m => StateMonad s (State s m) where ...

then we can derive an instance of ``StateMonad`` for ``Parser`` by ::

      newtype Parser tok m a = Parser (State [tok] (Failure m) a)
                             deriving (Monad, StateMonad [tok])

The derived instance is obtained by completing the application of the
class to the new type: ::

      instance StateMonad [tok] (State [tok] (Failure m)) =>
               StateMonad [tok] (Parser tok m)

As a result of this extension, all derived instances in newtype
declarations are treated uniformly (and implemented just by reusing the
dictionary for the representation type), *except* ``Show`` and ``Read``,
which really behave differently for the newtype and its representation.

.. note::

    It is sometimes necessary to enable additional language extensions when
    deriving instances via :extension:`GeneralizedNewtypeDeriving`. For instance,
    consider a simple class and instance using :extension:`UnboxedTuples`
    syntax: ::

        {-# LANGUAGE UnboxedTuples #-}

        module Lib where

        class AClass a where
          aMethod :: a -> (# Int, a #)

        instance AClass Int where
          aMethod x = (# x, x #)

    The following will fail with an "Illegal unboxed tuple" error, since the
    derived instance produced by the compiler makes use of unboxed tuple syntax,
    ::

        {-# LANGUAGE GeneralizedNewtypeDeriving #-}

        import Lib

        newtype Int' = Int' Int
                     deriving (AClass)

    However, enabling the :extension:`UnboxedTuples` extension allows the module
    to compile. Similar errors may occur with a variety of extensions,
    including:

      * :extension:`UnboxedTuples`
      * :extension:`PolyKinds`
      * :extension:`MultiParamTypeClasses`
      * :extension:`FlexibleContexts`

.. _precise-gnd-specification:

A more precise specification
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

A derived instance is derived only for declarations of these forms
(after expansion of any type synonyms) ::

      newtype T v1..vn                   = MkT (t vk+1..vn) deriving (C t1..tj)
      newtype instance T s1..sk vk+1..vn = MkT (t vk+1..vn) deriving (C t1..tj)

where

-  ``v1..vn`` are type variables, and ``t``, ``s1..sk``, ``t1..tj`` are
   types.

-  The ``(C t1..tj)`` is a partial applications of the class ``C``,
   where the arity of ``C`` is exactly ``j+1``. That is, ``C`` lacks
   exactly one type argument.

-  ``k`` is chosen so that ``C t1..tj (T v1...vk)`` is well-kinded. (Or,
   in the case of a ``data instance``, so that ``C t1..tj (T s1..sk)``
   is well kinded.)

-  The type ``t`` is an arbitrary type.

-  The type variables ``vk+1...vn`` do not occur in the types ``t``,
   ``s1..sk``, or ``t1..tj``.

-  ``C`` is not ``Read``, ``Show``, ``Typeable``, or ``Data``. These
   classes should not "look through" the type or its constructor. You
   can still derive these classes for a newtype, but it happens in the
   usual way, not via this new mechanism. Confer with
   :ref:`default-deriving-strategy`.

-  It is safe to coerce each of the methods of ``C``. That is, the
   missing last argument to ``C`` is not used at a nominal role in any
   of the ``C``'s methods. (See :ref:`roles`.)

- ``C`` is allowed to have associated type families, provided they meet the
  requirements laid out in the section on :ref:`GND and associated types
  <gnd-and-associated-types>`.

Then the derived instance declaration is of the form ::

      instance C t1..tj t => C t1..tj (T v1...vk)

Note that if ``C`` does not contain any class methods, the instance context
is wholly unnecessary, and as such GHC will instead generate: ::

      instance C t1..tj (T v1..vk)

As an example which does *not* work, consider ::

      newtype NonMonad m s = NonMonad (State s m s) deriving Monad

Here we cannot derive the instance ::

      instance Monad (State s m) => Monad (NonMonad m)

because the type variable ``s`` occurs in ``State s m``, and so cannot
be "eta-converted" away. It is a good thing that this ``deriving``
clause is rejected, because ``NonMonad m`` is not, in fact, a monad ---
for the same reason. Try defining ``>>=`` with the correct type: you
won't be able to.

Notice also that the *order* of class parameters becomes important,
since we can only derive instances for the last one. If the
``StateMonad`` class above were instead defined as ::

      class StateMonad m s | m -> s where ...

then we would not have been able to derive an instance for the
``Parser`` type above. We hypothesise that multi-parameter classes
usually have one "main" parameter for which deriving new instances is
most interesting.

Lastly, all of this applies only for classes other than ``Read``,
``Show``, ``Typeable``, and ``Data``, for which the stock derivation
applies (section 4.3.3. of the Haskell Report). (For the standard
classes ``Eq``, ``Ord``, ``Ix``, and ``Bounded`` it is immaterial
whether the stock method is used or the one described here.)

.. _gnd-and-associated-types:

Associated type families
~~~~~~~~~~~~~~~~~~~~~~~~

:extension:`GeneralizedNewtypeDeriving` also works for some type classes with
associated type families. Here is an example: ::

      class HasRing a where
        type Ring a

      newtype L1Norm a = L1Norm a
        deriving HasRing

The derived ``HasRing`` instance would look like ::

      instance HasRing (L1Norm a) where
        type Ring (L1Norm a) = Ring a

To be precise, if the class being derived is of the form ::

      class C c_1 c_2 ... c_m where
        type T1 t1_1 t1_2 ... t1_n
        ...
        type Tk tk_1 tk_2 ... tk_p

and the newtype is of the form ::

      newtype N n_1 n_2 ... n_q = MkN <rep-type>

then you can derive a ``C c_1 c_2 ... c_(m-1)`` instance for
``N n_1 n_2 ... n_q``, provided that:

- The type parameter ``c_m`` occurs once in each of the type variables of
  ``T1`` through ``Tk``. Imagine a class where this condition didn't hold.
  For example: ::

      class Bad a b where
        type B a

      instance Bad Int a where
        type B Int = Char

      newtype Foo a = Foo a
        deriving (Bad Int)

  For the derived ``Bad Int`` instance, GHC would need to generate something
  like this: ::

      instance Bad Int (Foo a) where
        type B Int = B ???

  Now we're stuck, since we have no way to refer to ``a`` on the right-hand
  side of the ``B`` family instance, so this instance doesn't really make sense
  in a :extension:`GeneralizedNewtypeDeriving` setting.

- ``C`` does not have any associated data families (only type families). To
  see why data families are forbidden, imagine the following scenario: ::

      class Ex a where
        data D a

      instance Ex Int where
        data D Int = DInt Bool

      newtype Age = MkAge Int deriving Ex

  For the derived ``Ex`` instance, GHC would need to generate something like
  this: ::

      instance Ex Age where
        data D Age = ???

  But it is not clear what GHC would fill in for ``???``, as each data family
  instance must generate fresh data constructors.

If both of these conditions are met, GHC will generate this instance: ::

      instance C c_1 c_2 ... c_(m-1) <rep-type> =>
               C c_1 c_2 ... c_(m-1) (N n_1 n_2 ... n_q) where
        type T1 t1_1 t1_2 ... (N n_1 n_2 ... n_q) ... t1_n
           = T1 t1_1 t1_2 ... <rep-type>          ... t1_n
        ...
        type Tk tk_1 tk_2 ... (N n_1 n_2 ... n_q) ... tk_p
           = Tk tk_1 tk_2 ... <rep-type>          ... tk_p

Again, if ``C`` contains no class methods, the instance context will be
redundant, so GHC will instead generate
``instance C c_1 c_2 ... c_(m-1) (N n_1 n_2 ... n_q)``.

Beware that in some cases, you may need to enable the
:extension:`UndecidableInstances` extension in order to use this feature.
Here's a pathological case that illustrates why this might happen: ::

      class C a where
        type T a

      newtype Loop = MkLoop Loop
        deriving C

This will generate the derived instance: ::

      instance C Loop where
        type T Loop = T Loop

Here, it is evident that attempting to use the type ``T Loop`` will throw the
typechecker into an infinite loop, as its definition recurses endlessly. In
other cases, you might need to enable :extension:`UndecidableInstances` even
if the generated code won't put the typechecker into a loop. For example: ::

      instance C Int where
        type C Int = Int

      newtype MyInt = MyInt Int
        deriving C

This will generate the derived instance: ::

      instance C MyInt where
        type T MyInt = T Int

Although typechecking ``T MyInt`` will terminate, GHC's termination checker
isn't sophisticated enough to determine this, so you'll need to enable
:extension:`UndecidableInstances` in order to use this derived instance. If
you do go down this route, make sure you can convince yourself that all of
the type family instances you're deriving will eventually terminate if used!

Note that :extension:`DerivingVia` (see :ref:`deriving-via`) uses essentially
the same specification to derive instances of associated type families as well
(except that it uses the ``via`` type instead of the underlying ``rep-type``
of a newtype).