summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Pickering <matthewtpickering@gmail.com>2015-11-19 13:50:01 +0000
committerMatthew Pickering <matthewtpickering@gmail.com>2015-11-19 13:51:58 +0000
commitb72ca3e3fa54b80a2c376e259cd09df60c7106bf (patch)
treea7df6c9c94c6fbe93d11a4decb0206fe8031dd2c
parentd732ce0d947565fb659f0b7058db5730ce04a6f7 (diff)
downloadhaskell-b72ca3e3fa54b80a2c376e259cd09df60c7106bf.tar.gz
Pattern Synonym Documentation
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
-rw-r--r--docs/users_guide/7.12.1-notes.rst30
-rw-r--r--docs/users_guide/glasgow_exts.rst180
2 files changed, 183 insertions, 27 deletions
diff --git a/docs/users_guide/7.12.1-notes.rst b/docs/users_guide/7.12.1-notes.rst
index 6364219e6b..f3c0ed43a6 100644
--- a/docs/users_guide/7.12.1-notes.rst
+++ b/docs/users_guide/7.12.1-notes.rst
@@ -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
~~~~~~~~
diff --git a/docs/users_guide/glasgow_exts.rst b/docs/users_guide/glasgow_exts.rst
index c88f7ba66f..4879624768 100644
--- a/docs/users_guide/glasgow_exts.rst
+++ b/docs/users_guide/glasgow_exts.rst
@@ -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