Require Export List.

Module Type OrdSet.

Variable A : Set.

Variable le : A -> A -> Prop.

Hypothesis le_trans : forall x y z, le x y -> le y z -> le x z.
Hypothesis le_total : forall x y, le x y + le y x.

End OrdSet.

Module Sort (O:OrdSet).
Import O.

Inductive le_list (x:A) : list A -> Prop := 
    le_list_nil : le_list x nil
  | le_list_cons : forall a l, le x a -> le_list x l -> le_list x (a::l).

Hint Constructors le_list.

Lemma le_le_list_trans 
     : forall a b l, le a b -> le_list b l -> le_list a l.
induction 2; auto.
apply le_list_cons; auto.
apply le_trans with b; trivial.
Save.

Inductive sorted : list A -> Prop := 
    sorted_nil : sorted nil
  | sorted_singl : forall a, sorted (a::nil)
  | sorted_cons : forall a b l, sorted (b::l) -> le a b 
                         -> sorted (a::b::l).
Hint Constructors sorted.

Lemma le_list_sorted : forall l a, sorted (a::l) -> le_list a l.
induction l; intros; auto.
inversion_clear H; auto.
apply le_list_cons; auto.
apply le_le_list_trans with a; auto.
Save.
Hint Immediate le_list_sorted.

Lemma sorted_le_list : 
forall a l, sorted l -> le_list a l -> sorted (a::l).
induction 1; intros; auto.
inversion H; auto.
inversion_clear H1; auto.
Save.
Hint Resolve sorted_le_list.

Inductive permut : list A -> list A -> Prop := 
    permul_nil : permut nil nil
 | permut_cons : forall a l1 l2, 
            permut l1 l2 -> permut (a::l1) (a::l2)
 | permut_cons2 : forall a b l1 l2, 
            permut (a::l1) l2 -> permut (a::b::l1) (b::l2)
 | permut_trans : forall l1 l2 l3, 
            permut l1 l2 -> permut l2 l3 -> permut l1 l3.
Hint Constructors permut.

Lemma permut_refl : forall l, permut l l.
induction l; auto.
Save.
Hint Resolve permut_refl.

Lemma le_list_permut : forall a l m, permut l m 
   -> le_list a l -> le_list a m.
induction 1; intros; auto.
inversion H0; auto.
inversion_clear H0; auto.
inversion H2; auto.
Save.

Lemma insertion : forall a l, sorted l -> {m| sorted m /\ permut (a::l) m}.
induction l; intro.
exists (a::nil); auto.
case (le_total a a0); intro.
exists (a::a0::l); split; auto.
assert (sorted l).
inversion H; auto.
case (IHl H0); intros m (Hs,Hp).
exists (a0::m); split; auto.
apply sorted_le_list; auto.
apply le_list_permut with (a::l); auto.
Defined.


Lemma sort : forall l, {m| sorted m /\ permut l m}.
induction l.
exists (nil (A:=A)); auto.
case IHl; intros l1 (Hsl1,Hpl1).
case (insertion a l1 Hsl1); intros l2 (Hsl2,Hpl2).
exists l2; split; auto.
apply permut_trans with (a::l1); auto.
Defined.

(*
Extraction sort.
Extraction insertion. 
*)
End Sort.
Extraction Sort.
Extraction "inssort.ml" Sort.
