... | ... | @@ -49,30 +49,33 @@ And now we can write |
|
|
isInt _ = False
|
|
|
```
|
|
|
|
|
|
## Pattern-only synonyms
|
|
|
|
|
|
Furthermore, pattern synonyms can also be used in expressions, e.g.,
|
|
|
|
|
|
```wiki
|
|
|
arrows :: [Type] -> Type -> Type
|
|
|
arrows = flip $ foldr Arrow
|
|
|
```
|
|
|
The simplest form of pattern synonyms is the one from the examples above. The grammar rule is:
|
|
|
|
|
|
## Simple pattern synonyms
|
|
|
`pattern`*conid**varid<sub>1</sub>* ... *varid<sub>n</sub>*`=`*pat*
|
|
|
|
|
|
`pattern`*varid<sub>1</sub>**consym**varid<sub>2</sub>*`=`*pat*
|
|
|
|
|
|
The simplest form of pattern synonyms is the one from the examples above. The grammar rule is:
|
|
|
- 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.
|
|
|
- The semantics is simply expansion of the synonym.
|
|
|
|
|
|
`pattern`*conid**varid<sub>1</sub>* ... *varid<sub>n</sub>*`=`*patexp*
|
|
|
|
|
|
Pattern synonyms can be exported and imported by prefixing the *conid* with the keyword `pattern`:
|
|
|
|
|
|
where *patexp* is the intersection of the grammars for patterns and expression, i.e., those terms that are valid both as a pattern and as an expression.
|
|
|
```wiki
|
|
|
module Foo (pattern Arrow) where ...
|
|
|
```
|
|
|
|
|
|
- Each of the variables on the left hand side must occur exactly once on the right hand side, and these are the only variables that can occur on the right hand side.
|
|
|
- Pattern synonyms are not allowed to be recursive. Cf. type synonyms.
|
|
|
- The semantics is simply expansion of the synonym.
|
|
|
|
|
|
This is required because pattern synonyms are in the namespace of constructors, so it's perfectly valid to have
|
|
|
|
|
|
Pattern synonyms can be exported and imported by mentioning the *conid* in the export/import list. Note that this suffers from the same constructor vs type confusion that already exists in a `hiding` list, i.e., given the mention of a *conid* you cannot tell if it refers to a constructor or a type.
|
|
|
```wiki
|
|
|
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:
|
... | ... | @@ -87,56 +90,55 @@ E.g. |
|
|
pattern Arrow t1 t2 = App "->" [t1, t2]
|
|
|
```
|
|
|
|
|
|
## Pattern only synonyms
|
|
|
|
|
|
Together with [ViewPatternsAlternative](view-patterns-alternative) we can now create patterns that look like regular patterns to match on existing (perhaps abstract) types in new ways.
|
|
|
|
|
|
Simple patterns synonyms are restricted to having a right hand side that is also a valid expression.
|
|
|
Pattern only synonyms can have any pattern on the right hand side, but may only be used in patterns.
|
|
|
```wiki
|
|
|
pattern Plus1 n = n1 | let n = n1-1, n >= 0
|
|
|
|
|
|
`pattern`*conid**varid<sub>1</sub>* ... *varid<sub>n</sub>*`=`*pat*
|
|
|
fac 0 = 0
|
|
|
fac (Plus1 n) = (n+1) * fac n
|
|
|
```
|
|
|
|
|
|
|
|
|
Again, each of the variables on the left hand side must be mentioned exactly once on the right hand side, but now the right hand side can mention other variables as well. These variables will not be bound when using the pattern synonym.
|
|
|
Note that the right hand side of `Plus1` binds `n1` and `n`, but since only `n` is mentioned on the left hand side it is the only variable that gets bound when `Plus1` is used.
|
|
|
|
|
|
|
|
|
Examples:
|
|
|
Another example showing pattern synonyms used as views, with regular [ViewPatterns](view-patterns):
|
|
|
|
|
|
```wiki
|
|
|
pattern ThirdElem x = _:_:x:_
|
|
|
pattern LazySecond a b = (a, ~b)
|
|
|
import qualified Data.Sequence as Seq
|
|
|
|
|
|
third (ThirdElem a) = a
|
|
|
third _ = error "No third"
|
|
|
|
|
|
fcn :: (Int, (Int, Int))
|
|
|
fcn (LazySecond x (y, z)) = if x == 0 then 0 else y+z
|
|
|
pattern Empty = (Seq.viewl -> Seq.EmptyL)
|
|
|
pattern x :< xs = (Seq.viewl -> x Seq.:< xs)
|
|
|
pattern xs :> x = (Seq.viewr -> xs Seq.:> x)
|
|
|
```
|
|
|
|
|
|
## Implicitly-bidirectional pattern synonyms
|
|
|
|
|
|
And their expansions
|
|
|
|
|
|
```wiki
|
|
|
third (_:_:a:_) = a
|
|
|
third _ = error "No third"
|
|
|
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 is said to be bidirectional, and can be used in expression contexts as well.
|
|
|
|
|
|
fcn :: (Int, (Int, Int))
|
|
|
fcn (x, ~(y, z)) = if x == 0 then 0 else y+z
|
|
|
```
|
|
|
|
|
|
|
|
|
Together with [ViewPatternsAlternative](view-patterns-alternative) we can now create patterns that look like regular patterns to match on existing (perhaps abstract) types in new ways.
|
|
|
For example, the following two are not bidirectional:
|
|
|
|
|
|
```wiki
|
|
|
pattern Plus1 n = n1 | let n = n1-1, n >= 0
|
|
|
|
|
|
fac 0 = 0
|
|
|
fac (Plus1 n) = (n+1) * fac n
|
|
|
pattern ThirdElem x = _:_:x:_
|
|
|
pattern Snd y = (x, y)
|
|
|
```
|
|
|
|
|
|
|
|
|
Note that the right hand side of `Plus1` binds `n1` and `n`, but since only `n` is mentioned on the left hand side it is the only variable that gets bound when `Plus1` is used.
|
|
|
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:
|
|
|
|
|
|
```wiki
|
|
|
arrows :: [Type] -> Type -> Type
|
|
|
arrows = flip $ foldr Arrow
|
|
|
```
|
|
|
|
|
|
## Bidirectional pattern synonyms
|
|
|
## Explicitly-bidirectional pattern synonyms
|
|
|
|
|
|
|
|
|
What if you want to use `Plus1` from the earlier example in an expression?
|
... | ... | |