but any Tree-specific pattern matching code you write will be wide and obscure. Turning these definitions into pattern synonyms means you can have both readable type-specific programs and handy generics without marshalling your data between views.

Uni-directional (pattern-only) synonyms

The simplest form of pattern synonyms is the one from the examples above. The grammar rule is:

patternconidvarid1 ... varidn<-pat

patternvarid1consymvarid2<-pat

Each of the variables on the left hand side must occur exactly once on the right hand side

Pattern synonyms are not allowed to be recursive. Cf. type synonyms.

TODO

There have been several proposals for the syntax of defining pattern-only synonyms:

patternconidvarid1 ... varidn~pat

patternconidvarid1 ... varidn:=pat

patternconidvarid1 ... varidn->pat

patternconidvarid1 ... varidn<-pat

Pattern synonyms can be exported and imported by prefixing the conid with the keyword pattern:

module Foo (pattern Arrow) where ...

This is required because pattern synonyms are in the namespace of constructors, so it's perfectly valid to have

data P = C
pattern P = 42

You may also give a type signature for a pattern, but as with most other type signatures in Haskell it is optional:

Simply-bidirectional pattern synonyms

In cases where pat is in the intersection of the grammars for patterns and expressions (i.e. is valid both as an expression and a pattern), the pattern synonym can be made bidirectional, and can be used in expression contexts as well. Bidirectional pattern synonyms have the following syntax:

patternconidvarid1 ... varidn=pat

patternvarid1consymvarid2=pat

For example, the following two pattern synonym definitions are rejected, because they are not bidirectional (but they would be valid as pattern-only synonyms)

pattern ThirdElem x = _:_:x:_
pattern Snd y = (x, y)

since the right-hand side is not a closed expression of {x} and {y} respectively.

In contrast, the pattern synonyms for Arrow and Int above are bidirectional, so you can e.g. write:

arrows :: [Type] -> Type -> Type
arrows = flip $ foldr Arrow

Explicitly-bidirectional pattern synonyms

What if you want to use Succ in an expression:

pattern Succ n <- n1 | let n = n1 -1, n >= 0

It's clearly impossible since its expansion is a pattern that has no meaning as an expression.
Nevertheless, if we want to make what looks like a constructor for a type we will often want to use it in both patterns and expressions.
This is the rationale for the most complicated synonyms, the bidirectional ones. They provide two expansions, one for patterns and one for expressions.

patternconidvarid1 ... varidn<-patwherecfunlhsrhs

where cfunlhs is like funlhs, except that the functions symbol is a conid instead of a varid.

One could go one step further and leave out the pattern keyword to obtain associated constructors, which are required to be bidirectional. The capitalized identifier would indicate that a pattern synonym is being defined. For complicated cases one could resort to the where syntax (shown above).

Typed pattern synonyms

So far patterns only had syntactic meaning. In comparison ​Ωmega has typed pattern synonyms, so they become first class values. (I am not suggesting this for Haskell, yet.)

Semantics

It might seem tempting to just define pattern synonym semantics as 'textual substitution'. On the other hand, just like with any other surface language feature, we don't want to normalize away pattern synonyms before typechecking happens, since we want to report type error occurrences from user-written code.

These two goals are incompatible once you start to factor in patterns containing typeclass-polymorphic parts. For example, let's say we have these two GADTs:

data S a where
MkS:: Num a -> a > S a
data T a where
MkT :: Eq a => a -> T a

which needs to use fromInteger from the Num instance provided by the MkS constructor to be able to pattern-match on the argument of the MkT constructor.

This means when we desugar a pattern synonym occurrence, the whole of the right-hand side needs to be matched before the arguments are matched. So the previous definition of f is desugared corresponding to the following Haskell code:

Of course, we don't actually generate Haskell code for that; instead, the implementation directly emits Core, in the same way Core is emitted for other pattern matchings (in DsUtils.mkCoAlgCaseMatchResult)