Section SortSeq.
Variables (T : Type) (leT : rel T).
Fixpoint merge s1 :=
if s1 is x1 :: s1' then
let fix merge_s1 s2 :=
if s2 is x2 :: s2' then
if leT x1 x2 then x1 :: merge s1' s2 else x2 :: merge_s1 s2'
else s1 in
merge_s1
else id.
Arguments merge !s1 !s2 : rename.
Fixpoint merge_sort_push s1 ss :=
match ss with
| [::] :: ss' | [::] as ss' => s1 :: ss'
| s2 :: ss' => [::] :: merge_sort_push (merge s2 s1) ss'
end.
Fixpoint merge_sort_pop s1 ss :=
if ss is s2 :: ss' then merge_sort_pop (merge s2 s1) ss' else s1.
Fixpoint merge_sort_rec ss s :=
if s is [:: x1, x2 & s'] then
let s1 := if leT x1 x2 then [:: x1; x2] else [:: x2; x1] in
merge_sort_rec (merge_sort_push s1 ss) s'
else merge_sort_pop s ss.
Definition sort := merge_sort_rec [::].
(* The following definition `sort_rec1` is an auxiliary function for          *)
(* inductive reasoning on `sort`. One can rewrite `sort le s` to              *)
(* `sort_rec1 le [::] s` by `sortE` and apply the simple structural induction *)
(* on `s` to reason about it.                                                 *)
Fixpoint sort_rec1 ss s :=
if s is x :: s then sort_rec1 (merge_sort_push [:: x] ss) s else
merge_sort_pop [::] ss.

Lemma sortE s : sort s = sort_rec1 [::] s.