
Require Compare.

Inductive list : Set :=
  nil : list
| cons : nat -> list -> list.

Inductive low [a:nat] : list -> Prop :=
 low_nil : (low a nil)
| low_cons : (l:list)(b:nat)(le a b)->
                         (low a (cons b l)).

Inductive sorted : list -> Prop :=
  sort_nil : (sorted nil)
| sort_cons : (l:list)(a:nat)(sorted l)->
                (low a l)->(sorted (cons a l)).


Inductive perm : list -> list -> Prop :=
  p_refl : (l:list)(perm l l)
| p_sym : (l1,l2:list)(perm l1 l2)->
            (perm l2 l1)
| p_trans : (l1,l2,l3:list)(perm l1 l2)->
              (perm l2 l3)->(perm l1 l3)
| p_cons : (a:nat)(l1,l2:list)(perm l1 l2)->
     (perm (cons a l1)(cons a l2))
| p_perm : (a,b:nat)(l:list)
      (perm (cons a (cons b l))
            (cons b (cons a l))).


Hints Resolve low_nil low_cons sort_nil 
      sort_cons p_refl.

Lemma ins : (l:list)(a:nat)(sorted l)->
    {l':list | (sorted l')
             /\(perm l' (cons a l))
             /\((b:nat)(le b a)->(low b l)->
                                     (low b l'))}.
Intros l a; Elim l.
Split with (cons a nil); Split; Auto; Split; Auto.

Clear l; Intros b l hl sl.
Elim (le_dec a b); Intro lab.
Split with (cons a (cons b l)); Split; Auto; Split; Auto.

Elim hl.
Intros x [sx [px hx]].
Split with (cons b x); Split; Auto.
Apply sort_cons; Auto.
Apply hx; Auto.
Inversion sl.
Auto.

Split; Auto.
Apply p_trans with (cons b (cons a l)).
Apply p_cons; Auto.

Apply p_perm.

Intro c; Intros; Apply low_cons.
Inversion H0.
Auto.

Inversion sl.
Auto.
Qed.

Extraction ins.


Lemma sort : (l:list){l':list |(sorted l')
                             /\(perm l l')}.
Induction l.
Split with nil; Split; Auto.

Clear l; Intros a l [l' [h1 h2]].
Elim (ins l' a).
Intros x [hx1 [hx2 hx3]]; Split with x; Split; Auto.
Apply p_sym.
Apply p_trans with (cons a l'); Auto.
Apply p_cons.
Auto.
Apply p_sym; Auto.

Auto.
Qed.

