Pattern Synonym Documentation
authorMatthew Pickering <matthewtpickering@gmail.com>
Thu, 19 Nov 2015 13:50:01 +0000 (13:50 +0000)
committerMatthew Pickering <matthewtpickering@gmail.com>
Thu, 19 Nov 2015 13:51:58 +0000 (13:51 +0000)
Summary:
This patch adds documentation for record pattern synonyms (D1258) and
bundling pattern synonyms with type constructors in export lists (D1152).

There are also other small improvements motivated by #10900.

Reviewers: goldfire, bgamari, austin

Reviewed By: bgamari

Subscribers: goldfire, thomie

Differential Revision: https://phabricator.haskell.org/D1325

GHC Trac Issues: #10900

docs/users_guide/7.12.1-notes.rst
docs/users_guide/glasgow_exts.rst

index 6364219..f3c0ed4 100644 (file)
@@ -81,6 +81,36 @@ Language
 -  The ``-XDeriveAnyClass`` extension now fills in associated type family
    default instances when deriving a class that contains them.
 
+-  Users can now define record pattern synonyms. This allows pattern synonyms
+   to behave more like normal data constructors. For example, ::
+
+      pattern P :: a -> b -> (a, b)
+      pattern P{x,y} = (x,y)
+
+   will allow `P` to be used like a record data constructor and also defines
+   selector functions `x :: (a, b) -> a` and `y :: (a, b) -> b`.
+
+-  Pattern synonyms can now be bundled with type constructors. For a pattern
+   synonym `P` and a type constructor `T`, `P` can be bundled with `T` so that
+   when `T` is imported `P` is also imported. With this change
+   a library author can provide either real data constructors or pattern
+   synonyms in an opaque manner. See :ref:`pattern-synonyms` for details. ::
+
+      -- Foo.hs
+      module Foo ( T(P) ) where
+
+      data T = T
+
+      pattern P = T
+
+      -- Baz.hs
+      module Baz where
+
+      -- P is imported
+      import Foo (T(..))
+
+
+
 Compiler
 ~~~~~~~~
 
index c88f7ba..4879624 100644 (file)
@@ -729,24 +729,97 @@ Which enables us to rewrite our functions in a much cleaner style:
       isIntEndo (Arrow Int Int) = True
       isIntEndo _               = False
 
-Note that in this example, the pattern synonyms ``Int`` and ``Arrow``
-can also be used as expressions (they are *bidirectional*). This is not
-necessarily the case: *unidirectional* pattern synonyms can also be
-declared with the following syntax:
+In general there are three kinds of pattern synonyms. Unidirectional,
+bidirectional and explicitly bidirectional. The examples given so far are
+examples of bidirectional pattern synonyms. A bidirectional synonym
+behaves the same as an ordinary data constructor. We can use it in a pattern
+context to deconstruct values and in an expression context to construct values.
+For example, we can construct the value `intEndo` using the pattern synonyms
+`Arrow` and `Int` as defined previously.
+
+::
+
+      intEndo :: Type
+      intEndo = Arrow Int Int
+
+This example is equivalent to the much more complicated construction if we had
+directly used the `Type` constructors.
+
+::
+
+      intEndo :: Type
+      intEndo = App "->" [App "Int" [], App "Int" []]
+
+
+Unidirectional synonyms can only be used in a pattern context and are
+defined as follows:
+
 
 ::
 
       pattern Head x <- x:xs
 
 In this case, ``Head`` ⟨x⟩ cannot be used in expressions, only patterns,
-since it wouldn't specify a value for the ⟨xs⟩ on the right-hand side.
-We can give an explicit inversion of a pattern synonym using the
-following syntax:
+since it wouldn't specify a value for the ⟨xs⟩ on the right-hand side. However,
+we can define an explicitly bidirectional pattern synonym by separately
+specifying how to construct and deconstruct a type. The syntax for
+doing this is as follows:
+
+::
+
+      pattern HeadC x <- x:xs where
+        HeadC x = [x]
+
+We can then use ``HeadC`` in both expression and pattern contexts. In a pattern
+context it will match the head of any list with length at least one. In an
+expression context it will construct a singleton list.
+
+The table below summarises where each kind of pattern synonym can be used.
+
++---------------+----------------+---------------+---------------------------+
+| Context       | Unidirectional | Bidirectional | Explicitly Bidirectional  |
++===============+================+===============+===========================+
+| Pattern       | Yes            | Yes           | Yes                       |
++---------------+----------------+---------------+---------------------------+
+| Expression    | No             | Yes (Inferred)| Yes (Explicit)            |
++---------------+----------------+---------------+---------------------------+
+
+Record Pattern Synonyms
+~~~~~~~~~~~~~~~~~~~~~~~
+
+It is also possible to define pattern synonyms which behave just like record
+constructors. The syntax for doing this is as follows:
+
+::
+
+      pattern Point :: (Int, Int)
+      pattern Point{x, y} = (x, y)
+
+The idea is that we can then use ``Point`` just as if we had defined a new
+datatype ``MyPoint`` with two fields ``x`` and ``y``.
 
 ::
 
-      pattern Head x <- x:xs where
-        Head x = [x]
+    data MyPoint = Point { x :: Int, y :: Int }
+
+Whilst a normal pattern synonym can be used in two ways, there are then seven
+ways in which to use ``Point``. Precisely the ways in which a normal record
+constructor can be used.
+
+=======================================   ==================================
+Usage                                     Example
+=======================================   ==================================
+As a constructor                          ``zero = Point 0 0``
+As a constructor with record syntax       ``zero = Point { x = 0, y = 0}``
+In a pattern context                      ``isZero (Point 0 0) = True``
+In a pattern context with record syntax   ``isZero (Point { x = 0, y = 0 }``
+In a pattern context with field puns      ``getX (Point {x}) = x``
+In a record update                        ``(0, 0) { x = 1 } == (1,0)``
+Using record selectors                    ``x (0,0) == 0``
+=======================================   ==================================
+
+For a unidirectional record pattern synonym we define record selectors but do
+not allow record updates or construction.
 
 The syntax and semantics of pattern synonyms are elaborated in the
 following subsections. See the :ghc-wiki:`Wiki page <PatternSynonyms>` for more
@@ -755,36 +828,48 @@ details.
 Syntax and scoping of pattern synonyms
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-A pattern synonym declaration can be either unidirectional or
-bidirectional. The syntax for unidirectional pattern synonyms is:
+A pattern synonym declaration can be either unidirectional,
+bidirectional or explicitly bidirectional.
+The syntax for unidirectional pattern synonyms is:
 
 ::
 
-      pattern Name args <- pat
+      pattern pat_lhs <- pat
 
-and the syntax for bidirectional pattern synonyms is:
+the syntax for bidirectional pattern synonyms is:
 
 ::
 
-      pattern Name args = pat
+      pattern pat_lhs = pat
 
-or
+and the syntax for explicitly bidirectional pattern synonyms is:
 
 ::
 
-      pattern Name args <- pat where
-        Name args = expr
+      pattern pat_lhs <- pat where
+        pat_lhs = expr
+
+We can define either prefix, infix or record pattern synonyms by modifying
+the form of `pat_lhs`. The syntax for these is as follows:
+
+======= ============================
+Prefix  ``Name args``
+------- ----------------------------
+Infix   ``arg1 `Name` arg2``
+        or ``arg1 op arg2``
+------- ----------------------------
+Record  ``Name{arg1,arg2,...,argn}``
+======= ============================
 
-Either prefix or infix syntax can be used.
 
 Pattern synonym declarations can only occur in the top level of a
 module. In particular, they are not allowed as local definitions.
 
 The variables in the left-hand side of the definition are bound by the
-pattern on the right-hand side. For implicitly bidirectional pattern
+pattern on the right-hand side. For bidirectional pattern
 synonyms, all the variables of the right-hand side must also occur on
 the left-hand side; also, wildcard patterns and view patterns are not
-allowed. For unidirectional and explicitly-bidirectional pattern
+allowed. For unidirectional and explicitly bidirectional pattern
 synonyms, there is no restriction on the right-hand side pattern.
 
 Pattern synonyms cannot be defined recursively.
@@ -794,16 +879,23 @@ Pattern synonyms cannot be defined recursively.
 Import and export of pattern synonyms
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-The name of the pattern synonym itself is in the same namespace as
-proper data constructors. In an export or import specification, you must
+The name of the pattern synonym is in the same namespace as proper data
+constructors. Like normal data constructors, pattern synonyms can be imported
+and exported through association with a type constructor or independently.
+
+To export them on their own, in an export or import specification, you must
 prefix pattern names with the ``pattern`` keyword, e.g.:
 
 ::
 
-      module Example (pattern Single) where
-      pattern Single x = [x]
+      module Example (pattern Zero) where
+
+      data MyNum = MkNum Int
+
+      pattern Zero :: MyNum
+      pattern Zero = MkNum 0
 
-Without the ``pattern`` prefix, ``Single`` would be interpreted as a
+Without the ``pattern`` prefix, ``Zero`` would be interpreted as a
 type constructor in the export list.
 
 You may also use the ``pattern`` keyword in an import/export
@@ -817,6 +909,37 @@ example:
 would bring into scope the data constructor ``Just`` from the ``Maybe``
 type, without also bringing the type constructor ``Maybe`` into scope.
 
+To bundle a pattern synonym with a type constructor, we list the pattern
+synonym in the export list of a module which exports the type constructor.
+For example, to bundle ``Zero`` with ``MyNum`` we could write the following:
+
+::
+
+      module Example ( MyNum(Zero) ) where
+
+If a module was then to import ``MyNum`` from ``Example``, it would also import
+the pattern synonym ``Zero``.
+
+It is also possible to use the special token ``..`` in an export list to mean
+all currently bundled constructors. For example, we could write:
+
+::
+
+      module Example ( MyNum(.., Zero) ) where
+
+in which case, ``Example`` would export the type constructor ``MyNum`` with
+the data constructor ``MkNum`` and also the pattern synonym ``Zero``.
+
+Bundled patterns synoyms are type checked to ensure that they are of the same
+type as the type constructor which they are bundled with. A pattern synonym
+`P` can not be bundled with a type constructor `T` if `P`'s type is visibly
+incompatible with `T`.
+
+A module which imports ``MyNum(..)`` from ``Example`` and then re-exports
+``MyNum(..)`` will also export any pattern synonyms bundled with ``MyNum`` in
+``Example``. A more complete specification can be found on the
+:ghc-wiki:`wiki. <PatternSynonyms/AssociatingSynonyms>`
+
 Typing of pattern synonyms
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -911,8 +1034,11 @@ Note also the following points
        data S a where
           S1 :: Bool -> S Bool
 
-       pattern P1 b = Just b  -- P1 ::                   Bool -> Maybe Bool
-       pattern P2 b = S1 b    -- P2 :: () => (b~Bool) => Bool -> S b
+       pattern P1 :: Bool -> Maybe Bool
+       pattern P1 b = Just b
+
+       pattern P2 :: () => (b ~ Bool) => Bool -> S b
+       pattern P2 b = S1 b
 
        f :: Maybe a -> String
        f (P1 x) = "no no no"     -- Type-incorrect