Recursive
datatypes
4 Datatypes are
described by several cases: the constructors
4 Each
constructor is presented as a function
4 Output type: the
datatype
4 Inputs: they
correpond to several fields
4 Some inputs are
in the datatype: recursion
4 Usually one constructor has no
inputs in the datatype (i.e. base cases)
4 Programming
function with the datatype as input
4 Use Match ...
with ... end
4 As many cases as
there are constructors
4 One pattern variable for each non
parameter constructor argument
An
example of recursive datatype
4 An example of datatype used to
describe a programming language
An
example of recursive function
4 Note the recursive calls made on tl and tr
4 The recursive
call should be done on strict sub-term
4 This ensure the
termination of recursive functions
Why
termination is important
An Ocaml
function:
# let rec loop x =loop x;; val f : 'a -> 'b = <fun>
Assume we can
do such a definition in Coq: Fixpoint loop (x:?) : ? := loop x.
Now add type
information for x: Fixpoint loop (x:nat) : ? := loop x.
Now add type information for the result (assume B:Type): Fixpoint
loop (x:nat) : B := loop x.
4 The function loop has type nat -> B
4 We have used B but we can use any type
Use False instead of bool:
Fixpoint loop (x:nat) : False := loop x.
4 Now the
function loop has type nat -> False
4 Did you see the
problem?
4 What is the type of loop 0 ?
loop 0 : False
4 We can proof False
without hypothesis, the
logical system is incoherent (everything is provable)
The termination
of recursive functions is one of the component
which ensure the
logical consistency of Coq
We should live
with it .. .
An
example of recursive function: fact
Recursive call
should be made on strict sub-term:
An
example of recursive function: div2
Recursive call
can be done on not immediate sub-terms:
A sub-term of
strict sub-term is a strict sub-term
More
general recursion
4 It is possible
to have recursive calls on results of functions
4 All cases must
return a strict sub-term
4 strict sub-terms may be obtained by
apply functions on strict sub-terms
4 Only constraint is that functions
must return sub-terms not necessarily strict.
4 Checked by
looking at all cases
Example
of function that returns a sub-term
4 in case O value is n, a
(non-strict) sub-term of n
4 in case S
p value is n
a sub-term of n
Recursive function
using pred
The same trick can be played with minus
which returns a
sub-term of its first argument, to define euclidian division
Mutual
recursion
It is possible
to define function by mutual recursion:
Lexicographic
order
Sometimes termination functions is
ensured by a lexicographic order on arguments (Ocaml):
let rec merge l1 l2 =
match l1, l2 with
| [], _ -> l2
| _, [] -> l1
| x1::l1', x2::l2' ->
if x1 <= x2 then
x1 :: merge l1' l2
else
x2 :: merge l1 l2';;
There are two
recursive calls merge l1' l2 and merge l1 l2'
Solution
in Coq: internal recursion
Coq also makes it possible to
describe anonymous recursive functions. Sometimes, it is
necessary to use them for difficult recursion patterns.
Another
solution (Hugo Herbelin)
More
general recursion
4 Constraint of
structural recursion too cumbersome
4 Sometimes a characteristic
decreases, but structural recursion is not available
4 General solution
provided by well-founded
recursion
4 Intermediate
solution provided by the command Function
Example using Function: fact on Z
Integers have a more complex structure than natural numbers
4 x − 1 is not a
structural sub-term of x
4 for instance 3
is Zpos (xI xH) and 2 is Zpos (xO xH)
4 Makes more
efficient computation possible
Now, we prove
explicitely that something decreases
Merge again
Well-founded
Relations
Partial order over a set of elements such that the minimal elements are accessible
Elements whose
all predecessors are accessible become accessible
A relation is
well founded if all elements are accessible.
It is possible to define functions by recursion on the accessibility
proof of an element (Function is based on this)
Proving
that some relation is well-founded
Coq's Standard Library provides us
with some useful examples of well-founded relations :
4 The predicate lt over nat (but you can use measure instead)
4 The predicate Zwf
c, which is the restriction of < to the interval [c, ∞] of Z.
More
example : log10
log10 can also be
defined using measure
Proving
properties on recursive functions
Usually a property on a recursive
function can be proved using an induction on the recursive argument.
Sometime we need some generalization
before starting the induction (see the example div2_le).
Proof
techniques for recursive function
4 Specific
reasoning tool for each function
4 Usable like an
induction principle
4 Requires a special induction tactic
4 Cases correspond
to behavior cases of function
4 Hypotheses are
provided for each test performed
4 Induction
hypotheses are provided for recursive calls
Example
of functional induction
Second
example of functional induction
Proof
techniques for mutual fixpoints
Properties on
mutual fixpoints should be generally proved
simultaneously.
Example:
Solution
1: prove both in one shot
Use the lemma
to prove the two disjoint lemmas:
Solution
2: use mutual lemmas
This is a way to
define a mutual fixpoint in proof mode.
Prove for function
defined using Function
Among the few lemmas that are generated by Function, the lemma log10_equation has the following statement, which expresses the
intention of the original definition :
Functional
Scheme
A functional scheme for function defined using Function is also
automatically generated (no need to use Functional
Scheme)
So, you can use functional induction .. .
Proofs
about uncurrified functions
4 Induction principles work for
variables, no composite expressions
4 All references to sub-components
must be explicit references to the argument
4 Two solutions to
make references explicit (see the proofs)
4 use projectors
4 add equalities
Generating
its own induction principle
Sometime, the
generated induction principle is not what you need.
You
have to build your own induction principle