Version 9 (modified by xrchz, 4 years ago) (diff)

minor typo-correction and rewording

Pattern Synonyms


Motivating example

Here is a simple representation of types

    data Type = App String [Type]


   collectArgs :: Type -> [Type]
   collectArgs _ = []

   isInt (App "Int" []) = True
   isInt _ = False


The proposal is to introduce a way to give patterns names:

   pattern Int = App "Int" []

And now we can write

   collectArgs :: Type -> [Type]
   collectArgs (Arrow t1 t2) = t1 : collectArgs t2
   collectArgs _ = []

   isInt Int = True
   isInt _ = False

Furthermore, pattern synonyms can also be used in expressions, e.g.,

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

Simple pattern synonyms


pattern conid varid1 ... varidn = patexp

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.

  • 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.
  • The semantics is simply expansion of the synonym.

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.


pattern conid :: type


   pattern Arrow :: Type -> Type -> Type

Pattern only synonyms

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.

pattern conid varid1 ... varidn = pat

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.


   pattern ThirdElem x = _:_:x:_
   pattern LazySecond a b ~ (a, ~b)

   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

And their expansions

   third (_:_:a:_) = a
   third _ = error "No third"

   fcn :: (Int, (Int, Int))
   fcn (x, ~(y, z)) = if x == 0 then 0 else y+z

Together with ViewPatternsAlternative we can now create patterns that look like regular patterns to match on existing (perhaps abstract) types in new ways.


   fac 0 = 0
   fac (Plus1 n) = (n+1) * fac n 

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.

Bidirectional pattern synonyms


pattern conid varid1 ... varidn = pat where cfunlhs rhs



      Plus1 n = n + 1


   fac 0 = 0
   fac (Plus1 n) = Plus1 n * fac n 

Associated Patterns Synonyms



   class ListLike l where
      pattern Nil :: l a
      pattern Cons :: a -> l a -> a
      isNil :: l a -> Bool
      isNil Nil = True
      isNil (Cons _ _) = False

   instance ListLike [] where
      pattern Nil = []
      pattern Cons x xs = x:xs
      append = (++)

   headOf Nil = Nothing
   headOf (Cons x _) = Just x