Raw File
deplist.v
(** Some programming with dependent types, based on Adam's book *)

Require Import Arith Bool List.
Require Coq.extraction.Extraction.
Extraction Language OCaml.
(** the standard fix point def*)
Fixpoint len (A : Set)(l : list A) : nat :=
  match l with
  | nil => 0
  | _ :: l' => S (len _ l')
                 end.
(* Print len. *)

(** Indexed lists*)
Set Implicit Arguments.

(** we assume some parameters to make declarations shorter:*)
Section ilist.
  Variable A : Set.
  Variable a : A.


(** the type of lists of length n:*)  
Inductive ilist : nat -> Set :=
  | Nil : ilist O
  | Cons : forall n, A -> ilist n -> ilist (S n).

(* Check Nil. 
Check (Cons a Nil). *)

(* Print ilist. *)

(** build a list of [n] copies of [a] *)

Fixpoint repeat n  : ilist n :=
  match n with
      | 0 => Nil
      | S m => Cons a (repeat m)
  end.

(* Print repeat.
Eval compute  in  repeat 5. *)

Fixpoint app n1 n2 (ls1 : ilist n1) (ls2 : ilist n2) : ilist (n1 + n2) :=
    match ls1 with
      | Nil => ls2
      | Cons  x ls1' => Cons x (app ls1' ls2)
    end.

(* Check app.
Print app. *)

Definition hd n (ls : ilist (S n)) : A :=
    match ls with
      | Cons  h _ => h
    end.

(* Check hd. *)


Definition tl n (ls : ilist (S n)) : (ilist n) :=
    match ls with
      | Cons   _ t => t
    end.

(* Check tl. *)


Fixpoint snoc n (ls : ilist n) (x : A) : ilist (S n) :=
    match ls with
      | Nil => Cons x Nil
      | Cons  y ls' => Cons y (snoc ls' x)
    end.

Fixpoint rev n (ls : ilist n)  : ilist n :=
    match ls with
      | Nil => Nil
      | Cons  x ys => (snoc (rev  ys) x)
    end.

(* Print rev. *)

(** Why didn't we define [rev] via [app]? Because it is not immediate:*)

(* Fail Fixpoint revapp n (ls : ilist n)  : ilist n :=
  match ls in (ilist n0)   return (ilist n0 ) with
      | Nil => Nil
      | Cons  x ys => app (revapp  ys) (Cons x Nil)
    end. *)
(* The term "app (revapp n0 ys) (Cons x Nil)" has type "ilist (n0 + 1)" while it is expected to have type "ilist (S n0)".*)

(** Since types depend on terms, namely [nats], type inference entails some theorem proving, here 
the easy theorem that [n0 + 1 = S n0]. The former is what the type of [app] requires, but the latter
is what the type of [rev] offers. In general, these lemmas may be arbitrarily difficult. They derive from the conversion rule
in the type theory of Coq --- roughly

[[[

Gamma |-  m : A t       Gamma |- t == s
-------------------------------------------------------
         Gamma |- m : A s 

]]]


Luckily we can use the [Program] package, which let us
_prove_ the additional proof obligations.

Note (or not) that we have to be more explicit about the
return type of each branch of the pattern matching.
*)

Program Fixpoint revapp n (ls : ilist n)  : ilist n :=
  match ls in (ilist n0)   return (ilist n0 ) with
      | Nil => Nil
      | Cons  x ys => app (revapp  ys) (Cons x Nil)
  end.
Obligation 1.
rewrite <- plus_n_Sm. rewrite <- plus_n_O. reflexivity.
Defined.
End ilist.



(*
Other types as spec that we'd like to express

- Red and black trees, where the invariant is preserved by the type itself
*)





Inductive color : Set := Red | Black.

Inductive rbtree : color -> nat -> Set :=
| Leaf : rbtree Black 0
| RedNode : forall n, rbtree Black n -> nat -> rbtree Black n -> rbtree Red n
| BlackNode : forall c1 c2 n, rbtree c1 n -> nat -> rbtree c2 n -> rbtree Black (S n).



(** A value of type [rbtree c d] is a red-black tree whose root has
color [c] and that has black depth [d].  The latter property means
that there are exactly [d] black-colored nodes on any path from the
root to a leaf. *)

(** Types that are more informative, allowing us to express the specification of the function
in the type signature. We consider a simple example: predecessor *)

(** the standard one *)
Definition pred (n : nat) : nat :=
  match n with
    | 0 => 0
    | S n' => n'
  end.

(** a useful lemma *)
Lemma zgtz: 0 > 0 -> False.
  intro.  inversion H.
Qed.

(** strenghening the precondition: *)
Definition pred_s1 (n : nat) : n > 0 -> nat :=
  match n with
    |0 => fun pf : 0 > 0 =>
            match zgtz pf with end
    | S n' => fun _ => n'
  end.


(* Print pred_s1. *)
(** Let's see what it looks like in OCaml:*)
(* Extraction pred_s1. *)

(** The _irrelevant_ proving part has been erased.*)

(** we can derive the same definition interactively. Note full stop after the type that
enters proving mode. *)

Definition pred_ss (n : nat) : n > 0 -> nat.
destruct n.
- intros. apply  zgtz in H. destruct H.
- intros. exact n.
Defined.
(* Print pred_ss. *)
(* Extraction pred_ss. *)

(** or we can use the [Program] library and*)
Program Definition pred_sp1 (n : nat)(pf:  n > 0 ) :  nat :=
    match n with
    | O => _
    | S n' => n'
    end.
Obligation 1.
apply zgtz in pf. exfalso. assumption.
Defined.

(* Extraction pred_s1. *)


(* The strongest spec, where we use subset types to say exactly what [pred] does:*)

Program Definition pred_strong6 (n : nat) (_ : n > 0) : {m : nat | n = S m} :=
  match n with
    | O => _
    | S n' => n'
  end.
Obligation 1.
intros. apply zgtz in H. exfalso. assumption.
Defined.

back to top