diff options
author | Matthew Pickering <matthewtpickering@gmail.com> | 2015-11-19 13:50:01 +0000 |
---|---|---|
committer | Matthew Pickering <matthewtpickering@gmail.com> | 2015-11-19 13:51:58 +0000 |
commit | b72ca3e3fa54b80a2c376e259cd09df60c7106bf (patch) | |
tree | a7df6c9c94c6fbe93d11a4decb0206fe8031dd2c | |
parent | d732ce0d947565fb659f0b7058db5730ce04a6f7 (diff) | |
download | haskell-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.rst | 30 | ||||
-rw-r--r-- | docs/users_guide/glasgow_exts.rst | 180 |
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 |