summaryrefslogtreecommitdiff
path: root/docs/users_guide/exts/record_wildcards.rst
blob: aff4cccf73d57c129f7a86688697d9447aa670f4 (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
.. _record-wildcards:

Record wildcards
----------------

.. extension:: RecordWildCards
    :shortdesc: Enable record wildcards.
        Implies :extension:`DisambiguateRecordFields`.

    :implies: :extension:`DisambiguateRecordFields`.
    :since: 6.8.1

    Allow the use of wildcards in record construction and pattern matching.

Record wildcards are enabled by the language extension :extension:`RecordWildCards`. This
extension implies :extension:`DisambiguateRecordFields`.

For records with many fields, it can be tiresome to write out each field
individually in a record pattern, as in ::

    data C = C {a :: Int, b :: Int, c :: Int, d :: Int}
    f (C {a = 1, b = b, c = c, d = d}) = b + c + d

Record wildcard syntax permits a "``..``" in a record pattern, where
each elided field ``f`` is replaced by the pattern ``f = f``. For
example, the above pattern can be written as ::

    f (C {a = 1, ..}) = b + c + d

More details:

-  Record wildcards in patterns can be mixed with other patterns,
   including puns (:ref:`record-puns`); for example, in a pattern
   ``(C {a = 1, b, ..})``. Additionally, record wildcards can be used
   wherever record patterns occur, including in ``let`` bindings and at
   the top-level. For example, the top-level binding ::

       C {a = 1, ..} = e

   defines ``b``, ``c``, and ``d``.

-  Record wildcards can also be used in an expression, when constructing
   a record. For example, ::

       let {a = 1; b = 2; c = 3; d = 4} in C {..}

   in place of ::

       let {a = 1; b = 2; c = 3; d = 4} in C {a=a, b=b, c=c, d=d}

   The expansion is purely syntactic, so the record wildcard expression
   refers to the nearest enclosing variables that are spelled the same
   as the omitted field names.

-  For both pattern and expression wildcards, the "``..``" expands to
   the missing *in-scope* record fields. Specifically the expansion of
   "``C {..}``" includes ``f`` if and only if:

   -  ``f`` is a record field of constructor ``C``.

   -  The record field ``f`` is in scope somehow (either qualified or
      unqualified).

   These rules restrict record wildcards to the situations in which the
   user could have written the expanded version. For example ::

       module M where
         data R = R { a,b,c :: Int }
       module X where
         import M( R(R,a,c) )
         f a b = R { .. }

   The ``R{..}`` expands to ``R{a=a}``, omitting ``b`` since the
   record field is not in scope, and omitting ``c`` since the variable
   ``c`` is not in scope (apart from the binding of the record selector
   ``c``, of course).

-  When record wildcards are used in record construction, a field ``f``
   is initialised only if ``f`` is in scope,
   and is not imported or bound at top level.
   For example, ``f`` can be bound by an enclosing pattern match or
   let/where-binding. For example ::

        module M where
          import A( a )

          data R = R { a,b,c,d :: Int }

          c = 3 :: Int

          f b = R { .. }  -- Expands to R { b = b, d = d }
            where
              d = b+1

   Here, ``a`` is imported, and ``c`` is bound at top level, so neither
   contribute to the expansion of the "``..``".
   The motivation here is that it should be
   easy for the reader to figure out what the "``..``" expands to.

-  Record wildcards cannot be used (a) in a record update construct, and
   (b) for data constructors that are not declared with record fields.
   For example: ::

       f x = x { v=True, .. }   -- Illegal (a)

       data T = MkT Int Bool
       g = MkT { .. }           -- Illegal (b)
       h (MkT { .. }) = True    -- Illegal (b)