diff options
author | Dr. ERDI Gergo <gergo@erdi.hu> | 2014-01-26 12:10:10 +0800 |
---|---|---|
committer | Dr. ERDI Gergo <gergo@erdi.hu> | 2014-01-26 12:10:10 +0800 |
commit | 5281dd6f5998af94aa06c3769089db7011ea4463 (patch) | |
tree | 6fe9fde7c6ebd3fb081d13c9b69ade0b56c10e7d /docs | |
parent | e01367ff8c3165b0dd1fb78bcb3a3ced1e4a5f19 (diff) | |
download | haskell-5281dd6f5998af94aa06c3769089db7011ea4463.tar.gz |
User documentation for pattern synonyms
Diffstat (limited to 'docs')
-rw-r--r-- | docs/users_guide/7.8.1-notes.xml | 6 | ||||
-rw-r--r-- | docs/users_guide/glasgow_exts.xml | 299 |
2 files changed, 304 insertions, 1 deletions
diff --git a/docs/users_guide/7.8.1-notes.xml b/docs/users_guide/7.8.1-notes.xml index c446b9d5a0..c1954bb242 100644 --- a/docs/users_guide/7.8.1-notes.xml +++ b/docs/users_guide/7.8.1-notes.xml @@ -126,7 +126,11 @@ allowing you to name and abstract over patterns more easily. - For more information, see TODO FIXME. + For more information, see <xref linkend="pattern-synonyms"/>. + </para> + <para> + Note: For the GHC 7.8.1 version, this language feature + should be regarded as a preview. </para> </listitem> diff --git a/docs/users_guide/glasgow_exts.xml b/docs/users_guide/glasgow_exts.xml index 141502d03d..77be1e7bf6 100644 --- a/docs/users_guide/glasgow_exts.xml +++ b/docs/users_guide/glasgow_exts.xml @@ -849,6 +849,296 @@ y)</literal> will not be coalesced. </sect2> + <!-- ===================== Pattern synonyms =================== --> + +<sect2 id="pattern-synonyms"> +<title>Pattern synonyms +</title> + +<para> +Pattern synonyms are enabled by the flag <literal>-XPatternSynonyms</literal>. +More information and examples of view patterns can be found on the +<ulink url="http://ghc.haskell.org/trac/ghc/wiki/PatternSynonyms">Wiki +page</ulink>. +</para> + +<para> +Pattern synonyms enable giving names to parametrized pattern +schemes. They can also be thought of as abstract constructors that +don't have a bearing on data representation. For example, in a +programming language implementation, we might represent types of the +language as follows: +</para> + +<programlisting> +data Type = App String [Type] +</programlisting> + +<para> +Here are some examples of using this representation: +Using this representation, a function type will look like this: +</para> + +<programlisting> + App "->" [t1, t2] -- t1 -> t2 + App "Int" [] -- Int + App "Maybe" [App "Int" []] -- Maybe Int +</programlisting> + +<para> +This representation is very generic in that no types are given special +treatment. However, some functions might need to handle some known +types specially, for example the following two functions collects all +argument types of (nested) arrow types, and recognize the +<literal>Int</literal> type, respectively: +</para> + +<programlisting> + collectArgs :: Type -> [Type] + collectArgs (App "->" [t1, t2]) = t1 : collectArgs t2 + collectArgs _ = [] + + isInt :: Type -> Bool + isInt (App "Int" []) = True + isInt _ = False +</programlisting> + +<para> +Matching on <literal>App</literal> directly is both hard to read and +error prone to write. And the situation is even worse when the +matching is nested: +</para> + +<programlisting> + isIntEndo :: Type -> Bool + isIntEndo (App "->" [App "Int" [], App "Int" []]) = True + isIntEndo _ = False +</programlisting> + +<para> +Pattern synonyms permit abstracting from the representation to expose +matchers that behave in a constructor-like manner with respect to +pattern matching. We can create pattern synonyms for the known types +we care about, without committing the representation to them (note +that these don't have to be defined in the same module as the +<literal>Type</literal> type): +</para> + +<programlisting> + pattern Arrow t1 t2 = App "->" [t1, t2] + pattern Int = App "Int" [] + pattern Maybe t = App "Maybe" [t] +</programlisting> + +<para> +Which enables us to rewrite our functions in a much cleaner style: +</para> + +<programlisting> + collectArgs :: Type -> [Type] + collectArgs (Arrow t1 t2) = t1 : collectArgs t2 + collectArgs _ = [] + + isInt :: Type -> Bool + isInt Int = True + isInt _ = False + + isIntEndo :: Type -> Bool + isIntEndo (Arrow Int Int) = True + isIntEndo _ = False +</programlisting> + +<para> + Note that in this example, the pattern synonyms + <literal>Int</literal> and <literal>Arrow</literal> can also be used + as expressions (they are <emphasis>bidirectional</emphasis>). This + is not necessarily the case: <emphasis>unidirectional</emphasis> + pattern synonyms can also be declared with the following syntax: +</para> + +<programlisting> + pattern Head x <- x:xs +</programlisting> + +<para> +In this case, <literal>Head</literal> <replaceable>x</replaceable> +cannot be used in expressions, only patterns, since it wouldn't +specify a value for the <replaceable>xs</replaceable> on the +right-hand side. +</para> + +<para> +The semantics of a unidirectional pattern synonym declaration and +usage are as follows: + +<itemizedlist> + +<listitem> Syntax: +<para> +A pattern synonym declaration can be either unidirectional or +bidirectional. The syntax for unidirectional pattern synonyms is: +</para> +<programlisting> + pattern Name args <- pat +</programlisting> +<para> + and the syntax for bidirectional pattern synonyms is: +</para> +<programlisting> + pattern Name args = pat +</programlisting> +<para> + Pattern synonym declarations can only occur in the top level of a + module. In particular, they are not allowed as local + definitions. Currently, they also don't work in GHCi, but that is a + technical restriction that will be lifted in later versions. +</para> +<para> + The name of the pattern synonym itself is in the same namespace as + proper data constructors. Either prefix or infix syntax can be + used. In export/import specifications, you have to prefix pattern + names with the <literal>pattern</literal> keyword, e.g.: +</para> +<programlisting> + module Example (pattern Single) where + pattern Single x = [x] +</programlisting> +</listitem> + +<listitem> Scoping: + +<para> + The variables in the left-hand side of the definition are bound by + the 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 pattern synonyms, there is no + restriction on the right-hand side pattern. +</para> + +<para> + Pattern synonyms cannot be defined recursively. +</para> + +</listitem> + +<listitem> Typing: + +<para> + Given a pattern synonym definition of the form +</para> +<programlisting> + pattern P var1 var2 ... varN <- pat +</programlisting> +<para> + it is assigned a <emphasis>pattern type</emphasis> of the form +</para> +<programlisting> + pattern CProv => P t1 t2 ... tN :: CReq => t +</programlisting> +<para> + where <replaceable>CProv</replaceable> and + <replaceable>CReq</replaceable> are type contexts, and + <replaceable>t1</replaceable>, <replaceable>t2</replaceable>, ..., + <replaceable>tN</replaceable> and <replaceable>t</replaceable> are + types. +</para> + +<para> +A pattern synonym of this type can be used in a pattern if the +instatiated (monomorphic) type satisfies the constraints of +<replaceable>CReq</replaceable>. In this case, it extends the context +available in the right-hand side of the match with +<replaceable>CProv</replaceable>, just like how an existentially-typed +data constructor can extend the context. +</para> + +<para> +For example, in the following program: +</para> +<programlisting> +{-# LANGUAGE PatternSynonyms, GADTs #-} +module ShouldCompile where + +data T a where + MkT :: (Show b) => a -> b -> T a + +pattern ExNumPat x = MkT 42 x +</programlisting> + +<para> +the pattern type of <literal>ExNumPat</literal> is +</para> + +<programlisting> +pattern (Show b) => ExNumPat b :: (Num a, Eq a) => T a +</programlisting> + +<para> + and so can be used in a function definition like the following: +</para> + +<programlisting> + f :: (Num t, Eq t) => T t -> String + f (ExNumPat x) = show x +</programlisting> + +<para> + For bidirectional pattern synonyms, uses as expressions have the type +</para> +<programlisting> + (CProv, CReq) => t1 -> t2 -> ... -> tN -> t +</programlisting> + +<para> + So in the previous example, <literal>ExNumPat</literal>, + when used in an expression, has type +</para> +<programlisting> + ExNumPat :: (Show b, Num a, Eq a) => b -> T t +</programlisting> + +</listitem> + +<listitem> Matching: + +<para> +A pattern synonym occurance in a pattern is evaluated by first +matching against the pattern synonym itself, and then on the argument +patterns. For example, in the following program, <literal>f</literal> +and <literal>f'</literal> are equivalent: +</para> + +<programlisting> +pattern Pair x y <- [x, y] + +f (Pair True True) = True +f _ = False + +f' [x, y] | True <- x, True <- y = True +f' _ = False +</programlisting> + +<para> + Note that the strictness of <literal>f</literal> differs from that + of <literal>g</literal> defined below: +</para> + +<programlisting> +g [True, True] = True +g _ = False + +*Main> f (False:undefined) +*** Exception: Prelude.undefined +*Main> g (False:undefined) +False +</programlisting> +</listitem> +</itemizedlist> +</para> + +</sect2> + <!-- ===================== n+k patterns =================== --> <sect2 id="n-k-patterns"> @@ -2327,6 +2617,15 @@ The following syntax is stolen: Stolen by: <option>-XBangPatterns</option> </para></listitem> </varlistentry> + + <varlistentry> + <term> + <literal>pattern</literal> + </term> + <listitem><para> + Stolen by: <option>-XPatternSynonyms</option> + </para></listitem> + </varlistentry> </variablelist> </para> </sect2> |