on 8063cfd help sign in
Idris-dev/tutorial/theorems.tex
417 lines 12 kB history raw
1\section{Theorem Proving}
3\subsection{Equality}
5\Idris{} allows propositional equalities to be declared, allowing theorems about
6programs to be stated and proved. Equality is built in, but conceptually has
7the following definition:
9\begin{SaveVerbatim}{}
11data (=) : a -> b -> Set where
12 refl : x = x
14\end{SaveVerbatim}
15\useverb{}
17\noindent
18Equalities can be proposed between any values of any types, but the only way to
19construct a proof of equality is if values actually are equal. For example:
21\begin{SaveVerbatim}{eqprf}
23fiveIsFive : 5 = 5
24fiveIsFive = refl
26twoPlusTwo : 2 + 2 = 4
27twoPlusTwo = refl
29\end{SaveVerbatim}
30\useverb{eqprf}
32\subsection{The Empty Type}
34\label{sect:empty}
36There is an empty type, \texttt{\_|\_}, which has no constructors. It is
37therefore impossible to construct an element of the empty type, at least
38without using a partially defined or general recursive function (see Section
39\ref{sect:totality} for more details). We can therefore use the empty type
40to prove that something is impossible, for example zero is never equal
41to a successor:
43\begin{SaveVerbatim}{natdisjoint}
45disjoint : (n : Nat) -> O = S n -> _|_
46disjoint n p = replace {P = disjointTy} p ()
47 where
48 disjointTy : Nat -> Set
49 disjointTy O = ()
50 disjointTy (S k) = _|_
52\end{SaveVerbatim}
53\useverb{natdisjoint}
55\noindent
56There is no need to worry too much about how this function works --- essentially,
57it applies the library function \texttt{replace}, which uses an equality proof to
58transform a predicate. Here we use it to transform a value of a type which can exist,
59the empty tuple, to a value of a type which can't, by using a proof of something
60which can't exist.
62Once we have an element of the empty type, we can prove anything. \texttt{FalseElim}
63is defined in the library, to assist with proofs by contradiction.
65\begin{SaveVerbatim}{falseelim}
67FalseElim : _|_ -> a
69\end{SaveVerbatim}
70\useverb{falseelim}
72\subsection{Simple Theorems}
74When type checking dependent types, the type itself gets \emph{normalised}. So imagine
75we want to prove the following theorem about the reduction behaviour of \texttt{plus}:
77\begin{SaveVerbatim}{plusred}
79plusReduces : (n:Nat) -> plus O n = n
81\end{SaveVerbatim}
82\useverb{plusred}
84\noindent
85We've written down the statement of the theorem as a type, in just the same way
86as we would write the type of a program. In fact there is no real distinction
87between proofs and programs. A proof, as far as we are concerned here, is
88merely a program with a precise enough type to guarantee a particular property
89of interest.
91We won't go into details here, but the Curry-Howard
92correspondence~\cite{howard} explains this relationship.
93The proof itself is trivial, because \texttt{plus O n} normalises to \texttt{n}
94by the definition of \texttt{plus}:
96\begin{SaveVerbatim}{plusredp}
98plusReduces n = refl
100\end{SaveVerbatim}
101\useverb{plusredp}
103\noindent
104It is slightly harder if we try the arguments the other way, because plus is
105defined by recursion on its first argument. The proof also works by recursion
106on the first argument to \texttt{plus}, namely \texttt{n}.
108\begin{SaveVerbatim}{plusRedO}
110plusReducesO : (n:Nat) -> n = plus n O
111plusReducesO O = refl
112plusReducesO (S k) = cong (plusReducesO k)
114\end{SaveVerbatim}
115\useverb{plusRedO}
117\noindent
118\texttt{cong} is a function defined in the library which states that
119equality respects function application:
121\begin{SaveVerbatim}{resps}
123cong : {f : t -> u} -> a = b -> f a = f b
125\end{SaveVerbatim}
126\useverb{resps}
128\noindent
129We can do the same for the reduction behaviour of plus on successors:
131\begin{SaveVerbatim}{plusRedS}
133plusReducesS : (n:Nat) -> (m:Nat) -> S (plus n m) = plus n (S m)
134plusReducesS O m = refl
135plusReducesS (S k) m = cong (plusReducesS k m)
137\end{SaveVerbatim}
138\useverb{plusRedS}
140\noindent
141Even for trival theorems like these, the proofs are a little tricky to
142construct in one go. When things get even slightly more complicated, it becomes
143too much to think about to construct proofs in this 'batch mode'. \Idris{}
144therefore provides an interactive proof mode.
146\subsection{Interactive theorem proving}
148Instead of writing the proof in one go, we can use \Idris{}'s interactive
149proof mode. To do this, we write the general \emph{structure} of the proof,
150and use the interactive mode to complete the details. We'll be constructing
151the proof by \emph{induction}, so we write the cases for \texttt{O} and
152\texttt{S}, with a recursive call in the \texttt{S} case giving the inductive
153hypothesis, and insert \emph{metavariables} for the rest of the definition:
155\begin{SaveVerbatim}{prOstruct}
157plusReducesO' : (n:Nat) -> n = plus n O
158plusReducesO' O = ?plusredO_O
159plusReducesO' (S k) = let ih = plusReducesO' k in
160 ?plusredO_S
162\end{SaveVerbatim}
163\useverb{prOstruct}
165\noindent
166On running \Idris{}, two global names are created, \texttt{plusredO\_O} and
167\texttt{plusredO\_S}, with no definition. We can use the \texttt{:m} command
168at the prompt to find out which metavariables are still to be solved (or, more
169precisely, which functions exist but have no definitions), then the
170\texttt{:t} command to see their types:
172\begin{SaveVerbatim}{showmetas}
174*theorems> :m
175Global metavariables:
176 [plusredO_S,plusredO_O]
178\end{SaveVerbatim}
180\begin{SaveVerbatim}{metatypes}
182*theorems> :t plusredO_O
183plusredO_O : O = plus O O
185*theorems> :t plusredO_S
186plusredO_S : (k : Nat) -> (k = plus k O) -> S k = S (plus k O)
188\end{SaveVerbatim}
189\useverb{showmetas}
191\useverb{metatypes}
193\noindent
194The \texttt{:p} command enters interactive proof mode, which can be used to complete
195the missing definitions.
197\begin{SaveVerbatim}{proveO}
199*theorems> :p plusredO_O
201---------------------------------- (plusredO_O) --------
202{hole0} : O = plus O O
204\end{SaveVerbatim}
205\useverb{proveO}
207\noindent
208This gives us a list of premisses
209(above the line; there are none here) and the current goal (below the line;
210named \texttt{\{hole0\}} here).
211At the prompt we can enter tactics to direct the construction of the proof. In this case,
212we can normalise the goal with the \texttt{compute} tactic:
214\begin{SaveVerbatim}{compute}
216-plusredO_O> compute
218---------------------------------- (plusredO_O) --------
219{hole0} : O = O
221\end{SaveVerbatim}
222\useverb{compute}
224\noindent
225Now we have to prove that \texttt{O} equals \texttt{O}, which is easy to prove by
226\texttt{refl}. To apply a function, such as \texttt{refl}, we use \texttt{refine}
227which introduces subgoals for each of the function's explicit arguments (\texttt{refl}
228has none):
230\begin{SaveVerbatim}{refrefl}
232-plusredO_O> refine refl
233plusredO_O: no more goals
235\end{SaveVerbatim}
236\useverb{refrefl}
238\noindent
239Here, we could also have used the \texttt{trivial} tactic, which tries to refine by
240\texttt{refl}, and if that fails, tries to refine by each name in the local context.
241When a proof is complete, we use the \texttt{qed} tactic to add the proof to the
242global context, and remove the metavariable from the unsolved metavariables list.
243This also outputs a trace of the proof:
245\begin{SaveVerbatim}{prOprooftrace}
247-plusredO_O> qed
248plusredO_O = proof {
249 compute;
250 refine refl;
253\end{SaveVerbatim}
254\useverb{prOprooftrace}
256\begin{SaveVerbatim}{showmetasO}
258*theorems> :m
259Global metavariables:
260 [plusredO_S]
262\end{SaveVerbatim}
263\useverb{showmetasO}
265\noindent
266The \texttt{:addproof} command, at the interactive prompt, will add the proof to
267the source file (effectively in an appendix).
268Let us now prove the other required lemma, \texttt{plusredO\_S}:
270\begin{SaveVerbatim}{plusredOSprf}
272*theorems> :p plusredO_S
274---------------------------------- (plusredO_S) --------
275{hole0} : (k : Nat) -> (k = plus k O) -> S k = S (plus k O)
277\end{SaveVerbatim}
278\useverb{plusredOSprf}
280\noindent
281In this case, the goal is a function type, using \texttt{k} (the argument accessible by
282pattern matching) and \texttt{ih} (the local variable containing the result of
283the recursive call). We can introduce these as premisses using the \texttt{intro} tactic
284twice (or \texttt{intros}, which introduces all arguments as premisses). This gives:
286\begin{SaveVerbatim}{prSintros}
288 k : Nat
289 ih : k = plus k O
290---------------------------------- (plusredO_S) --------
291{hole2} : S k = S (plus k O)
293\end{SaveVerbatim}
294\useverb{prSintros}
296\noindent
297We know, from the type of \texttt{ih}, that \texttt{k = plus k O}, so we would like to
298use this knowledge to replace \texttt{plus k O} in the goal with \texttt{k}. We can
299achieve this with the \texttt{rewrite} tactic:
301\begin{SaveVerbatim}{}
303-plusredO_S> rewrite ih
305 k : Nat
306 ih : k = plus k O
307---------------------------------- (plusredO_S) --------
308{hole3} : S k = S k
310-plusredO_S>
312\end{SaveVerbatim}
313\useverb{}
315\noindent
316The \texttt{rewrite} tactic takes an equality proof as an argument, and tries to rewrite
317the goal using that proof. Here, it results in an equality which is trivially provable:
319\begin{SaveVerbatim}{prOStrace}
321-plusredO_S> trivial
322plusredO_S: no more goals
323-plusredO_S> qed
324plusredO_S = proof {
325 intros;
326 rewrite ih;
327 trivial;
330\end{SaveVerbatim}
331\useverb{prOStrace}
333\noindent
334Again, we can add this proof to the end of our source file using the \texttt{:addproof}
335command at the interactive prompt.
337\subsection{Totality Checking}
339\label{sect:totality}
341If we really want to trust our proofs, it is important that they are defined by
342\emph{total} functions --- that is, a function which is defined for all possible inputs
343and is guaranteed to terminate. Otherwise we could construct an element of the empty type,
344from which we could prove anything:
346\begin{SaveVerbatim}{empties}
348-- making use of 'hd' being partially defined
349empty1 : _|_
350empty1 = hd [] where
351 hd : List a -> a
352 hd (x :: xs) = x
354-- not terminating
355empty2 : _|_
356empty2 = empty2
358\end{SaveVerbatim}
359\useverb{empties}
361\noindent
362Internally, \Idris{} checks every definition for totality, and we can check at the prompt
363with the \texttt{:total} command. We see that neither of the above definitions is total:
365\begin{SaveVerbatim}{totalcheck}
367*theorems> :total empty1
368possibly not total due to: empty1#hd
369 not total as there are missing cases
370*theorems> :total empty2
371possibly not total as it is not well founded
373\end{SaveVerbatim}
374\useverb{totalcheck}
376\noindent
377Note the use of the word ``possibly'' --- a totality check can, of course, never be certain
378due to the undecidability of the halting problem. The check is, therefore, conservative.
379It is also possible (and indeed advisable, in the case of proofs) to mark functions as
380total so that it will be a compile time error for the totality check to fail:
382\begin{SaveVerbatim}{emptyfail}
384total empty2 : _|_
385empty2 = empty2
387Type checking ./theorems.idr
388theorems.idr:25:empty2 is possibly not total as it is not well founded
390\end{SaveVerbatim}
391\useverb{emptyfail}
393\noindent
394Reassuringly, our proof in Section \ref{sect:empty} that the zero and successor constructors
395are disjoint is total:
397\begin{SaveVerbatim}{totdisjoint}
399*theorems> :total disjoint
400Total
402\end{SaveVerbatim}
403\useverb{totdisjoint}
405\noindent
406The totality check is currently very conservative. To be recorded as total, a function must:
408\begin{itemize}
409\item Cover all possible inputs
410\item Be \emph{well-founded} --- i.e. each recursive call must have a decreasing argument
411\item Not call any non-total functions
412\item Not use any data types which are not \emph{strictly positive}
413\item (In version 0.9.2) Not be mutually recursive
414\end{itemize}
416\noindent
417The last of these conditions may be relaxed in the future.