ListsWorking with Structured Data

Pairs of Numbers

Here's an Inductive with just one constructor (taking two arguments):
Inductive natprod : Type :=
| pair (n1 n2 : nat).
We define extraction functions by pattern matching.
Definition fst (p : natprod) : nat :=
  match p with
  | pair x yx
  end.

Definition snd (p : natprod) : nat :=
  match p with
  | pair x yy
  end.

A nicer notation for pairs:
Notation "( x , y )" := (pair x y).
The new pair notation can be used both in expressions and in pattern matches.
Compute (fst (3,5)).

Definition fst' (p : natprod) : nat :=
  match p with
  | (x,y) ⇒ x
  end.

Definition snd' (p : natprod) : nat :=
  match p with
  | (x,y) ⇒ y
  end.

Definition swap_pair (p : natprod) : natprod :=
  match p with
  | (x,y) ⇒ (y,x)
  end.

Lists of Numbers

An inductive definition of lists of numbers:
Inductive natlist : Type :=
  | nil
  | cons (n : nat) (l : natlist).

Definition mylist := cons 1 (cons 2 (cons 3 nil)).

Some notation for lists to make our lives easier:
Notation "x :: l" := (cons x l)
                     (at level 60, right associativity).
Notation "[ ]" := nil.
Notation "[ x ; .. ; y ]" := (cons x .. (cons y nil) ..).
Now these all mean exactly the same thing:
Definition mylist1 := 1 :: (2 :: (3 :: nil)).
Definition mylist2 := 1 :: 2 :: 3 :: nil.
Definition mylist3 := [1;2;3].

Repeat

Some useful list-manipulation functions:
Fixpoint repeat (n count : nat) : natlist :=
  match count with
  | Onil
  | S count'n :: (repeat n count')
  end.

Length


Fixpoint length (l:natlist) : nat :=
  match l with
  | nilO
  | h :: tS (length t)
  end.

Append


Fixpoint app (l1 l2 : natlist) : natlist :=
  match l1 with
  | nill2
  | h :: th :: (app t l2)
  end.

Notation "x ++ y" := (app x y)
                     (right associativity, at level 60).

Head (With Default) and Tail


Definition hd (default:nat) (l:natlist) : nat :=
  match l with
  | nildefault
  | h :: th
  end.

Definition tl (l:natlist) : natlist :=
  match l with
  | nilnil
  | h :: tt
  end.

Reasoning About Lists

As for numbers, some proofs about list functions need only simplification...
Theorem nil_app : l:natlist,
  [] ++ l = l.
Proof. reflexivity. Qed.

...and some need case analysis.
Theorem tl_length_pred : l:natlist,
  pred (length l) = length (tl l).
Proof.
  intros l. destruct l as [| n l'].
  - (* l = nil *)
    reflexivity.
  - (* l = cons n l' *)
    reflexivity. Qed.
Usually, though, interesting theorems about lists require induction for their proofs.

Induction on Lists

Coq generates an induction principle for every Inductive definition, including lists. We can use the induction tactic on lists to prove things like the associativity of list-append...
Theorem app_assoc : l1 l2 l3 : natlist,
  (l1 ++ l2) ++ l3 = l1 ++ (l2 ++ l3).
Proof.
  intros l1 l2 l3. induction l1 as [| n l1' IHl1'].
  - (* l1 = nil *)
    reflexivity.
  - (* l1 = cons n l1' *)
    simpl. rewriteIHl1'. reflexivity. Qed.

Reversing a List

A bigger example of induction over lists.
Fixpoint rev (l:natlist) : natlist :=
  match l with
  | nilnil
  | h :: trev t ++ [h]
  end.

Properties of rev

Let's try to prove length (rev l) = length l.
Theorem rev_length_firsttry : l : natlist,
  length (rev l) = length l.
Proof.
  intros l. induction l as [| n l' IHl'].
  - (* l = nil *)
    reflexivity.
  - (* l = n :: l' *)
    simpl.
    rewrite <- IHl'.
Abort.
We can prove a lemma to bridge the gap.


Theorem app_length : l1 l2 : natlist,
  length (l1 ++ l2) = (length l1) + (length l2).
Proof.
  (* WORK IN CLASS *) Admitted.


Theorem rev_length : l : natlist,
  length (rev l) = length l.
Proof.
  intros l. induction l as [| n l' IHl'].
  - (* l = nil *)
    reflexivity.
  - (* l = cons *)
    simpl. rewriteapp_length.
    simpl. rewriteIHl'. rewrite plus_comm.
    reflexivity.
Qed.

Options



Inductive natoption : Type :=
  | Some (n : nat)
  | None.


Fixpoint nth_error (l:natlist) (n:nat) : natoption :=
  match l with
  | nilNone
  | a :: l'match n =? O with
               | trueSome a
               | falsenth_error l' (pred n)
               end
  end.

We can also write this function using Coq's "if" expressions.
Fixpoint nth_error' (l:natlist) (n:nat) : natoption :=
  match l with
  | nilNone
  | a :: l'if n =? O then Some a
               else nth_error' l' (pred n)
  end.