summaryrefslogtreecommitdiff
path: root/docs/users_guide/exts/impredicative_types.rst
blob: 2380526fb6a9ffc596bf6fe5df2bf2e7e52fe197 (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
.. _impredicative-polymorphism:

Impredicative polymorphism
==========================

.. extension:: ImpredicativeTypes
    :shortdesc: Enable impredicative types.
        Implies :extension:`RankNTypes`.

    :implies: :extension:`RankNTypes`
    :since: 6.10.1

    Allow impredicative polymorphic types.

In general, GHC will only instantiate a polymorphic function at a
monomorphic type (one with no foralls). For example, ::

    runST :: (forall s. ST s a) -> a
    id :: forall b. b -> b

    foo = id runST   -- Rejected

The definition of ``foo`` is rejected because one would have to
instantiate ``id``\'s type with ``b := (forall s. ST s a) -> a``, and
that is not allowed. Instantiating polymorphic type variables with
polymorphic types is called *impredicative polymorphism*.

GHC has extremely flaky support for *impredicative polymorphism*,
enabled with :extension:`ImpredicativeTypes`. If it worked, this would mean
that you *could* call a polymorphic function at a polymorphic type, and
parameterise data structures over polymorphic types. For example: ::

      f :: Maybe (forall a. [a] -> [a]) -> Maybe ([Int], [Char])
      f (Just g) = Just (g [3], g "hello")
      f Nothing  = Nothing

Notice here that the ``Maybe`` type is parameterised by the
*polymorphic* type ``(forall a. [a] -> [a])``. However *the extension
should be considered highly experimental, and certainly un-supported*.
You are welcome to try it, but please don't rely on it working
consistently, or working the same in subsequent releases. See
:ghc-wiki:`this wiki page <impredicative-polymorphism>` for more details.

If you want impredicative polymorphism, the main workaround is to use a
newtype wrapper. The ``id runST`` example can be written using this
workaround like this: ::

    runST :: (forall s. ST s a) -> a
    id :: forall b. b -> b

    newtype Wrap a = Wrap { unWrap :: (forall s. ST s a) -> a }

    foo :: (forall s. ST s a) -> a
    foo = unWrap (id (Wrap runST))
          -- Here id is called at monomorphic type (Wrap a)