aboutsummaryrefslogtreecommitdiff
path: root/doc/Cases.tex
diff options
context:
space:
mode:
authorfilliatr2000-12-12 22:36:15 +0000
committerfilliatr2000-12-12 22:36:15 +0000
commitb6018c78b25da14d4f44cf10de692f968cba1e98 (patch)
treec152b9761b70cbc554efdc2f05f3a995444ed259 /doc/Cases.tex
parent88e2679b89a32189673b808acfe3d6181a38c000 (diff)
Initial revision
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@8143 85f007b7-540e-0410-9357-904b9bb8a0f7
Diffstat (limited to 'doc/Cases.tex')
-rw-r--r--doc/Cases.tex610
1 files changed, 610 insertions, 0 deletions
diff --git a/doc/Cases.tex b/doc/Cases.tex
new file mode 100644
index 0000000000..559c9e15b7
--- /dev/null
+++ b/doc/Cases.tex
@@ -0,0 +1,610 @@
+\achapter{ML-style pattern-matching}\defaultheaders
+\aauthor{Cristina Cornes}
+
+\label{Mult-Cases-full}
+\ttindex{Cases}
+\index{ML-like patterns}
+
+This section describes the full form of pattern-matching in {\Coq} terms.
+
+The current implementation contains two strategies, one for compiling
+non-dependent case and another one for dependent case.
+
+\asection{Patterns}\label{implementation}
+The full syntax of {\tt Cases} is presented in figure \ref{cases-grammar}.
+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
+{\em simple}: it is the kind of pattern recognized by the basic
+version of {\tt Cases}. If a pattern is
+not simple we call it {\em nested}.
+
+A variable pattern matches any value, and the identifier is bound to
+that value. The pattern ``\texttt{\_}'' (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 \texttt{(}{\sl pattern} \texttt{as} {\sl identifier}\texttt{)} are
+also accepted. This pattern matches the same values as {\sl pattern}
+does and {\sl identifier} is bound to the matched value. A list of
+patterns is also considered as a pattern and is called {\em multiple
+pattern}.
+
+Note also the annotation is mandatory when the sequence of equation is
+empty.
+
+\begin{figure}[t]
+\fbox{\parbox{\linewidth}{
+\begin{tabular}{rcl}
+{\nestedpattern} & := & {\ident} \\
+ & $|$ & \_ \\
+ & $|$ & \texttt{(} {\ident} \nelist{\nestedpattern}{} \texttt{)} \\
+ & $|$ & \texttt{(} {\nestedpattern} \texttt{as} {\ident} \texttt{)} \\
+ & $|$ & \texttt{(} {\nestedpattern} \texttt{,} {\nestedpattern} \texttt{)} \\
+ & $|$ & \texttt{(} {\nestedpattern} \texttt{)} \\
+ &&\\
+
+{\multpattern} & := & \nelist{nested\_pattern}{} \\
+ && \\
+
+{\exteqn} & := & {\multpattern} \texttt{=>} {\term} \\
+ && \\
+
+{\term} & := &
+ \zeroone{\annotation} \texttt{Cases} \nelist{\term}{} \texttt{of}
+ \sequence{\exteqn}{$|$} \texttt{end} \\
+\end{tabular}
+}}
+\caption{Extended Cases syntax}
+\label{cases-grammar}
+\end{figure}
+
+Since extended {\tt 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
+\texttt{Print} if the term is a constant, or using the command
+\texttt{Check}.
+
+The extended \texttt{Cases} still accepts an optional {\em elimination
+predicate} enclosed between brackets \texttt{<>}. Given a pattern
+matching expression, if all the right hand sides of \texttt{=>} ({\em
+rhs} in short) have the same type, then this term can be sometimes
+synthesized, and so we can omit the \texttt{<>}. Otherwise we have
+toprovide the predicate between \texttt{<>} as for the basic
+\texttt{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:
+
+\begin{coq_example}
+Fixpoint max [n,m:nat] : nat :=
+ Cases n of
+ O => m
+ | (S n') => Cases m of
+ O => (S n')
+ | (S m') => (S (max n' m'))
+ end
+ end.
+\end{coq_example}
+
+Using multiple patterns in the definition allows to write:
+
+\begin{coq_example}
+Reset max.
+Fixpoint max [n,m:nat] : nat :=
+ Cases n m of
+ O _ => m
+ | (S n') O => (S n')
+ | (S n') (S m') => (S (max n' m'))
+ end.
+\end{coq_example}
+
+which will be compiled into the previous form.
+
+The strategy examines patterns from left to right. A \texttt{Cases} expression
+is generated {\bf only} when there is at least one constructor in the
+column of patterns. For example:
+
+\begin{coq_example}
+Check [x:nat]<nat>Cases x of y => y end.
+\end{coq_example}
+
+We can also use ``\texttt{as} patterns'' to associate a name to a
+sub-pattern:
+
+\begin{coq_example}
+Reset max.
+Fixpoint max [n:nat] : nat -> nat :=
+ [m:nat] Cases n m of
+ O _ => m
+ | ((S n') as N) O => N
+ | (S n') (S m') => (S (max n' m'))
+ end.
+\end{coq_example}
+
+Here is now an example of nested patterns:
+
+\begin{coq_example}
+Fixpoint even [n:nat] : bool :=
+ Cases n of
+ O => true
+ | (S O) => false
+ | (S (S n')) => (even n')
+ end.
+\end{coq_example}
+
+This is compiled into:
+
+\begin{coq_example}
+Print even.
+\end{coq_example}
+
+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 \texttt{lef} that given two natural numbers
+yields \texttt{true} if the first one is less or equal than the second
+one and \texttt{false} otherwise. We can write it as follows:
+
+\begin{coq_example}
+Fixpoint lef [n,m:nat] : bool :=
+ Cases n m of
+ O x => true
+ | x O => false
+ | (S n) (S m) => (lef n m)
+ end.
+\end{coq_example}
+
+Note that the first and the second multiple pattern superpose because
+the couple of values \texttt{O O} matches both. Thus, what is the result
+of the function on those values? To eliminate ambiguity we use the
+{\em 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,
+\texttt{O O} is matched by the first pattern, and so \texttt{(lef O O)}
+yields \texttt{true}.
+
+Another way to write this function is:
+
+\begin{coq_example}
+Reset lef.
+Fixpoint lef [n,m:nat] : bool :=
+ Cases n m of
+ O x => true
+ | (S n) (S m) => (lef n m)
+ | _ _ => false
+ end.
+\end{coq_example}
+
+
+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,
+\begin{coq_example}
+Check [x:nat]Cases x of O => true | (S _) => false | x => true end.
+\end{coq_example}
+
+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.
+
+
+
+\asection{About patterns of parametric types}
+When matching objects of a parametric type, constructors in patterns
+{\em do not expect} the parameter arguments. Their value is deduced
+during expansion.
+
+Consider for example the polymorphic lists:
+
+\begin{coq_example}
+Inductive List [A:Set] :Set :=
+ nil:(List A)
+| cons:A->(List A)->(List A).
+\end{coq_example}
+
+We can check the function {\em tail}:
+
+\begin{coq_example}
+Check [l:(List nat)]Cases l of
+ nil => (nil nat)
+ | (cons _ l') => l'
+ end.
+\end{coq_example}
+
+
+When we use parameters in patterns there is an error message:
+\begin{coq_example}
+Check [l:(List nat)]Cases l of
+ (nil nat) => (nil nat)
+ | (cons nat _ l') => l'
+ end.
+\end{coq_example}
+
+
+
+\asection{Matching objects of dependent types}
+The previous examples illustrate pattern matching on objects of
+non-dependent types, but we can also
+use the expansion strategy to destructure objects of dependent type.
+Consider the type \texttt{listn} of lists of a certain length:
+
+\begin{coq_example}
+Inductive listn : nat-> Set :=
+ niln : (listn O)
+| consn : (n:nat)nat->(listn n) -> (listn (S n)).
+\end{coq_example}
+
+\asubsection{Understanding dependencies in patterns}
+We can define the function \texttt{length} over \texttt{listn} by:
+
+\begin{coq_example}
+Definition length := [n:nat][l:(listn n)] n.
+\end{coq_example}
+
+Just for illustrating pattern matching,
+we can define it by case analysis:
+\begin{coq_example}
+Reset length.
+Definition length := [n:nat][l:(listn n)]
+ Cases l of
+ niln => O
+ | (consn n _ _) => (S n)
+ end.
+\end{coq_example}
+
+We can understand the meaning of this definition using the
+same notions of usual pattern matching.
+
+Now suppose we split the second pattern of \texttt{length} into two
+cases so to give an
+alternative definition using nested patterns:
+\begin{coq_example}
+Definition length1:= [n:nat] [l:(listn n)]
+ Cases l of
+ niln => O
+ | (consn n _ niln) => (S n)
+ | (consn n _ (consn _ _ _)) => (S n)
+ end.
+\end{coq_example}
+
+It is obvious that \texttt{length1} is another version of
+\texttt{length}. We can also give the following definition:
+\begin{coq_example}
+Definition length2:= [n:nat] [l:(listn n)]
+ Cases l of
+ niln => O
+ | (consn n _ niln) => (S O)
+ | (consn n _ (consn m _ _)) => (S (S m))
+ end.
+\end{coq_example}
+
+If we forget that \texttt{listn} is a dependent type and we read these
+definitions using the usual semantics of pattern matching, we can conclude
+that \texttt{length1}
+and \texttt{length2} are different functions.
+In fact, they are equivalent
+because the pattern \texttt{niln} implies that \texttt{n} can only match
+the value $0$ and analogously the pattern \texttt{consn} determines that \texttt{n} can
+only match values of the form $(S~v)$ where $v$ is the value matched by
+\texttt{m}.
+
+The converse is also true. If
+we destructure the length value with the pattern \texttt{O} then the list
+value should be $niln$.
+Thus, the following term \texttt{length3} corresponds to the function
+\texttt{length} but this time defined by case analysis on the dependencies instead of on the list:
+
+\begin{coq_example}
+Definition length3 := [n:nat] [l: (listn n)]
+ Cases l of
+ niln => O
+ | (consn O _ _) => (S O)
+ | (consn (S n) _ _) => (S (S n))
+ end.
+\end{coq_example}
+
+When we have nested patterns of dependent types, the semantics of
+pattern matching becomes a little more difficult because
+the set of values that are matched by a sub-pattern may be conditioned by the
+values matched by another sub-pattern. Dependent nested patterns are
+somehow constrained patterns.
+In the examples, the expansion of
+\texttt{length1} and \texttt{length2} yields exactly the same term
+ but the
+expansion of \texttt{length3} is completely different. \texttt{length1} and
+\texttt{length2} are expanded into two nested case analysis on
+\texttt{listn} while \texttt{length3} is expanded into a case analysis on
+\texttt{listn} containing a case analysis on natural numbers inside.
+
+
+In practice the user can think about the patterns as independent and
+it is the expansion algorithm that cares to relate them. \\
+
+
+\asubsection{When the elimination predicate must be provided}
+The examples given so far do not need an explicit elimination predicate
+between \texttt{<>} because all the rhs have the same type and the
+strategy succeeds to synthesize it.
+Unfortunately when dealing with dependent patterns it often happens
+that we need to write cases where the type of the rhs are
+different instances of the elimination predicate.
+The function \texttt{concat} for \texttt{listn}
+is an example where the branches have different type
+and we need to provide the elimination predicate:
+
+\begin{coq_example}
+Fixpoint concat [n:nat; l:(listn n)]
+ : (m:nat) (listn m) -> (listn (plus n m))
+ := [m:nat][l':(listn m)]
+ <[n:nat](listn (plus n m))>Cases l of
+ niln => l'
+ | (consn n' a y) => (consn (plus n' m) a (concat n' y m l'))
+ end.
+\end{coq_example}
+
+Recall that a list of patterns is also a pattern. So, when
+we destructure several terms at the same time and the branches have
+different type we need to provide
+the elimination predicate for this multiple pattern.
+
+For example, an equivalent definition for \texttt{concat} (even though with a useless extra pattern) would have
+been:
+
+\begin{coq_example}
+Reset concat.
+Fixpoint concat [n:nat; l:(listn n)] : (m:nat) (listn m) -> (listn (plus n m))
+:= [m:nat][l':(listn m)]
+ <[n,_:nat](listn (plus n m))>Cases l l' of
+ niln x => x
+ | (consn n' a y) x => (consn (plus n' m) a (concat n' y m x))
+ end.
+\end{coq_example}
+
+Note that this time, the predicate \texttt{[n,\_:nat](listn (plus n
+ m))} is binary because we
+destructure both \texttt{l} and \texttt{l'} whose types have arity one.
+In general, if we destructure the terms $e_1\ldots e_n$
+the predicate will be of arity $m$ where $m$ is the sum of the
+number of dependencies of the type of $e_1, e_2,\ldots e_n$
+(the $\lambda$-abstractions
+should correspond from left to right to each dependent argument of the
+type of $e_1\ldots e_n$).
+When the arity of the predicate (i.e. number of abstractions) is not
+correct Coq rises an error message. For example:
+
+\begin{coq_example}
+Fixpoint concat [n:nat; l:(listn n)]
+ : (m:nat) (listn m) -> (listn (plus n m)) :=
+ [m:nat][l':(listn m)]
+ <[n:nat](listn (plus n m))>Cases l l' of
+ | niln x => x
+ | (consn n' a y) x => (consn (plus n' m) a (concat n' y m x))
+ end.
+\end{coq_example}
+
+\asection{Using pattern matching to write proofs}
+In all the previous examples the elimination predicate does not depend
+on the object(s) matched. The typical case where this is not possible
+is when we write a proof by induction or a function that yields an
+object of dependent type. An example of proof using \texttt{Cases} in
+given in section \ref{Refine-example}
+
+For example, we can write
+the function \texttt{buildlist} that given a natural number
+$n$ builds a list length $n$ containing zeros as follows:
+
+\begin{coq_example}
+Fixpoint buildlist [n:nat] : (listn n) :=
+ <[n:nat](listn n)>Cases n of
+ O => niln
+ | (S n) => (consn n O (buildlist n))
+ end.
+\end{coq_example}
+
+We can also use multiple patterns whenever the elimination predicate has
+the correct arity.
+
+Consider the following definition of the predicate less-equal
+\texttt{Le}:
+
+\begin{coq_example}
+Inductive LE : nat->nat->Prop :=
+ LEO: (n:nat)(LE O n)
+| LES: (n,m:nat)(LE n m) -> (LE (S n) (S m)).
+\end{coq_example}
+
+We can use multiple patterns to write the proof of the lemma
+ \texttt{(n,m:nat) (LE n m)\/(LE m n)}:
+
+\begin{coq_example}
+Fixpoint dec [n:nat] : (m:nat)(LE n m) \/ (LE m n) :=
+ [m:nat] <[n,m:nat](LE n m) \/ (LE m n)>Cases n m of
+ O x => (or_introl ? (LE x O) (LEO x))
+ | x O => (or_intror (LE x O) ? (LEO x))
+ | ((S n) as N) ((S m) as M) =>
+ Cases (dec n m) of
+ (or_introl h) => (or_introl ? (LE M N) (LES n m h))
+ | (or_intror h) => (or_intror (LE N M) ? (LES m n h))
+ end
+ end.
+\end{coq_example}
+In the example of \texttt{dec} the elimination predicate is binary
+because we destructure two arguments of \texttt{nat} that is a
+non-dependent type. Note the first \texttt{Cases} is dependent while the
+second is not.
+
+In general, consider the terms $e_1\ldots e_n$,
+where the type of $e_i$ is an instance of a family type
+$[\vec{d_i}:\vec{D_i}]T_i$ ($1\leq i
+\leq n$). Then to write \texttt{<}${\cal P}$\texttt{>Cases} $e_1\ldots
+e_n$ \texttt{of} \ldots \texttt{end}, the
+elimination predicate ${\cal P}$ should be of the form:
+$[\vec{d_1}:\vec{D_1}][x_1:T_1]\ldots [\vec{d_n}:\vec{D_n}][x_n:T_n]Q.$
+
+The user can also use \texttt{Cases} in combination with the tactic
+\texttt{Refine} (see section \ref{Refine}) to build incomplete proofs
+beginning with a \texttt{Cases} construction.
+
+\asection{When does the expansion strategy fail ?}\label{limitations}
+The strategy works very like in ML languages when treating
+patterns of non-dependent type.
+But there are new cases of failure that are due to the presence of
+dependencies.
+
+The error messages of the current implementation may be sometimes
+confusing. When the tactic fails because patterns are somehow
+incorrect then error messages refer to the initial expression. But the
+strategy may succeed to build an expression whose sub-expressions are
+well typed when the whole expression is not. In this situation the
+message makes reference to the expanded expression. We encourage
+users, when they have patterns with the same outer constructor in
+different equations, to name the variable patterns in the same
+positions with the same name.
+E.g. to write {\small\texttt{(cons n O x) => e1}}
+and {\small\texttt{(cons n \_ x) => e2}} instead of
+{\small\texttt{(cons n O x) => e1}} and
+{\small\texttt{(cons n' \_ x') => e2}}.
+This helps to maintain certain name correspondence between the
+generated expression and the original.
+
+Here is a summary of the error messages corresponding to each situation:
+
+\begin{itemize}
+\item patterns are incorrect (because constructors are not applied to
+ the correct number of the arguments, because they are not linear or
+ they are wrongly typed)
+\begin{itemize}
+\item \sverb{In pattern } {\sl term} \sverb{the constructor } {\sl
+ ident} \sverb{expects } {\sl num} \sverb{arguments}
+
+\item \sverb{The variable } {\sl ident} \sverb{is bound several times
+ in pattern } {\sl term}
+
+\item \sverb{Constructor pattern: } {\sl term} \sverb{cannot match
+ values of type } {\sl term}
+\end{itemize}
+
+\item the pattern matching is not exhaustive
+\begin{itemize}
+\item \sverb{This pattern-matching is not exhaustive}
+\end{itemize}
+\item the elimination predicate provided to \texttt{Cases} has not the
+ expected arity
+
+\begin{itemize}
+\item \sverb{The elimination predicate } {\sl term} \sverb{should be
+ of arity } {\sl num} \sverb{(for non dependent case) or } {\sl
+ num} \sverb{(for dependent case)}
+\end{itemize}
+
+\item the whole expression is wrongly typed, or the synthesis of
+ implicit arguments fails (for example to find the elimination
+ predicate or to resolve implicit arguments in the rhs).
+
+
+ There are {\em nested patterns of dependent type}, the elimination
+ predicate corresponds to non-dependent case and has the form
+ $[x_1:T_1]...[x_n:T_n]T$ and {\bf some} $x_i$ occurs {\bf free} in
+ $T$. Then, the strategy may fail to find out a correct elimination
+ predicate during some step of compilation. In this situation we
+ recommend the user to rewrite the nested dependent patterns into
+ several \texttt{Cases} with {\em simple patterns}.
+
+ In all these cases we have the following error message:
+
+ \begin{itemize}
+ \item {\tt Expansion strategy failed to build a well typed case
+ expression. There is a branch that mismatches the expected
+ type. The risen \\ type error on the result of expansion was:}
+ \end{itemize}
+
+\item because of nested patterns, it may happen that even though all
+ the rhs have the same type, the strategy needs dependent elimination
+ and so an elimination predicate must be provided. The system warns
+ about this situation, trying to compile anyway with the
+ non-dependent strategy. The risen message is:
+\begin{itemize}
+\item {\tt Warning: This pattern matching may need dependent
+ elimination to be compiled. I will try, but if fails try again
+ giving dependent elimination predicate.}
+\end{itemize}
+
+\item there are {\em nested patterns of dependent type} and the
+ strategy builds a term that is well typed but recursive calls in fix
+ point are reported as illegal:
+\begin{itemize}
+\item {\tt Error: Recursive call applied to an illegal term ...}
+\end{itemize}
+
+This is because the strategy generates a term that is correct w.r.t.
+to the initial term but which does not pass the guard condition. In
+this situation we recommend the user to transform the nested dependent
+patterns into {\em several \texttt{Cases} of simple patterns}. Let us
+explain this with an example. Consider the following definition of a
+function that yields the last element of a list and \texttt{O} if it is
+empty:
+
+\begin{coq_example}
+ Fixpoint last [n:nat; l:(listn n)] : nat :=
+ Cases l of
+ (consn _ a niln) => a
+ | (consn m _ x) => (last m x) | niln => O
+ end.
+\end{coq_example}
+
+It fails because of the priority between patterns, we know that this
+definition is equivalent to the following more explicit one (which
+fails too):
+
+\begin{coq_example*}
+ Fixpoint last [n:nat; l:(listn n)] : nat :=
+ Cases l of
+ (consn _ a niln) => a
+ | (consn n _ (consn m b x)) => (last n (consn m b x))
+ | niln => O
+ end.
+\end{coq_example*}
+
+Note that the recursive call {\tt (last n (consn m b x))} is not
+guarded. When treating with patterns of dependent types the strategy
+interprets the first definition of \texttt{last} as the second
+one\footnote{In languages of the ML family the first definition would
+ be translated into a term where the variable \texttt{x} is shared in
+ the expression. When patterns are of non-dependent types, Coq
+ compiles as in ML languages using sharing. When patterns are of
+ dependent types the compilation reconstructs the term as in the
+ second definition of \texttt{last} so to ensure the result of
+ expansion is well typed.}. Thus it generates a term where the
+recursive call is rejected by the guard condition.
+
+You can get rid of this problem by writing the definition with
+\emph{simple patterns}:
+
+\begin{coq_example}
+ Fixpoint last [n:nat; l:(listn n)] : nat :=
+ <[_:nat]nat>Cases l of
+ (consn m a x) => Cases x of niln => a | _ => (last m x) end
+ | niln => O
+ end.
+\end{coq_example}
+
+\end{itemize}
+
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: "Reference-Manual"
+%%% End: