13.1 Patterns

13.1 Patterns

The full syntax of Cases is presented in figure 13.1. Identifiers in patterns are either constructor names or variables. Any identifier that is not the constructor of an inductive or coinductive type is considered to be a variable. A variable name cannot occur more than once in a given pattern.

If a pattern has the form (c vec(x)) where c is a constructor symbol and vec(x) is a linear vector of variables, it is called simple: it is the kind of pattern recognized by the basic version of Cases. If a pattern is not simple we call it nested.

A variable pattern matches any value, and the identifier is bound to that value. The pattern ``_'' (called ``don't care'' or ``wildcard'' symbol) also matches any value, but does not binds anything. It may occur an arbitrary number of times in a pattern. Alias patterns written (pattern as identifier) are also accepted. This pattern matches the same values as pattern does and identifier is bound to the matched value. A list of patterns is also considered as a pattern and is called multiple pattern.

Note also the annotation is mandatory when the sequence of equation is empty.


nested_pattern := ident
  | _
  | ( ident nested_pattern ... nested_pattern )
  | ( nested_pattern as ident )
  | ( nested_pattern , nested_pattern )
  | ( nested_pattern )
     


mult_pattern
:= nested_pattern ... nested_pattern
     


ext_eqn
:= mult_pattern => term
     


term
:= [annotation] Cases term ... term of [ext_eqn | ... | ext_eqn] end


Figure 13.1:Extended Cases syntax



Since extended Cases expressions are compiled into the primitive ones, the expressiveness of the theory remains the same. Once the stage of parsing has finished only simple patterns remain. An easy way to see the result of the expansion is by printing the term with Print if the term is a constant, or using the command Check.

The extended Cases still accepts an optional elimination predicate enclosed between brackets <>. Given a pattern matching expression, if all the right hand sides of => (rhs in short) have the same type, then this term can be sometimes synthesized, and so we can omit the <>. Otherwise we have toprovide the predicate between <> as for the basic Cases.

Let us illustrate through examples the different aspects of extended pattern matching. Consider for example the function that computes the maximum of two natural numbers. We can write it in primitive syntax by:

Coq < Fixpoint max [n,m:nat] : nat :=
Coq < Cases n of
Coq < O => m
Coq < | (S n') => Cases m of
Coq < O => (S n')
Coq < | (S m') => (S (max n' m'))
Coq < end
Coq < end.
max is recursively defined


Using multiple patterns in the definition allows to write:

Coq < Reset max.

Coq < Fixpoint max [n,m:nat] : nat :=
Coq < Cases n m of
Coq < O _ => m
Coq < | (S n') O => (S n')
Coq < | (S n') (S m') => (S (max n' m'))
Coq < end.
max is recursively defined


which will be compiled into the previous form.

The strategy examines patterns from left to right. A Cases expression is generated only when there is at least one constructor in the column of patterns. For example:

Coq < Check [x:nat]<nat>Cases x of y => y end.
[x:nat]x
     : nat->nat


We can also use ``as patterns'' to associate a name to a sub-pattern:

Coq < Reset max.

Coq < Fixpoint max [n:nat] : nat -> nat :=
Coq < [m:nat] Cases n m of
Coq < O _ => m
Coq < | ((S n') as N) O => N
Coq < | (S n') (S m') => (S (max n' m'))
Coq < end.
Warning: the variable N starts with upper case in a pattern
max is recursively defined


Here is now an example of nested patterns:

Coq < Fixpoint even [n:nat] : bool :=
Coq < Cases n of
Coq < O => true
Coq < | (S O) => false
Coq < | (S (S n')) => (even n')
Coq < end.
even is recursively defined


This is compiled into:

Coq < Print even.
even = 
Fix even{even [n:nat] : bool := 
           Cases n of
             O => true
           | (S a) => Cases a of
                        O => false
                      | (S n') => (even n')
                      end
           end}
     : nat->bool


In the previous examples patterns do not conflict with, but sometimes it is comfortable to write patterns that admits a non trivial superposition. Consider the boolean function lef that given two natural numbers yields true if the first one is less or equal than the second one and false otherwise. We can write it as follows:

Coq < Fixpoint lef [n,m:nat] : bool :=
Coq < Cases n m of
Coq < O x => true
Coq < | x O => false
Coq < | (S n) (S m) => (lef n m)
Coq < end.
lef is recursively defined


Note that the first and the second multiple pattern superpose because the couple of values O O matches both. Thus, what is the result of the function on those values? To eliminate ambiguity we use the textual priority rule: we consider patterns ordered from top to bottom, then a value is matched by the pattern at the ith row if and only if is not matched by some pattern of a previous row. Thus in the example, O O is matched by the first pattern, and so (lef O O) yields true.

Another way to write this function is:

Coq < Reset lef.

Coq < Fixpoint lef [n,m:nat] : bool :=
Coq < Cases n m of
Coq < O x => true
Coq < | (S n) (S m) => (lef n m)
Coq < | _ _ => false
Coq < end.
lef is recursively defined


Here the last pattern superposes with the first two. Because of the priority rule, the last pattern will be used only for values that do not match neither the first nor the second one.

Terms with useless patterns are accepted by the system. For example,
Coq < Check [x:nat]Cases x of O => true | (S _) => false | x => true end.
[x:nat]Cases x of
         O => true
       | (S _) => false
       end
     : nat->bool


is accepted even though the last pattern is never used. Beware, the current implementation rises no warning message when there are unused patterns in a term.



Retrieved by Memoweb from http://pauillac.inria.fr/coq/doc/node.3.2.0.html at 8/10/98