module TreeSortInstance where

open import Prelude

record ⌜_⌝ (P : Set) : Set where
  constructor !
  field {{prf}} : P

-- Comparing natural numbers

Total : ∀{A} (R : Rel A)  Set
Total R =  x y   R (x , y)    R (y , x) 

pattern le = inl !
pattern ge = inr !

compare : Total LEℕ
compare 0       _       = le
compare (suc x) 0       = ge
compare (suc x) (suc y) = compare x y

-- Extension by a least and a greatest element

data Ext (A : Set) : Set where
   : Ext A
  # : A  Ext A
   : Ext A

ext : ∀{A}  Rel A  Rel (Ext A)
ext R (_   ,   ) = True
ext R (# x , # y) = R (x , y)
ext R (   , _  ) = True
ext R _           = False

module _ {A : Set} (R : Rel A) (compare : Total R) where

  -- Binary search trees

  data BST (lu : Ext A × Ext A) : Set where
    leaf : {{l≤u : ext R lu}}  BST lu
    node : (p : A)
           (let (l , u) = lu)
           (lt : BST (l , # p))
           (rt : BST (# p , u))  BST lu

  insert : ∀{l u : Ext A} (p : A) {{l≤p : ext R (l , # p)}} {{p≤u : ext R (# p , u)}}
           (t : BST (l , u))  BST (l , u)
  insert p leaf = node p leaf leaf
  insert p (node q lt rt) with compare p q
  ... | le = node q (insert p lt) rt
  ... | ge = node q lt (insert p rt)


  -- Building a BST

  tree : (xs : List A)  BST ( , )
  tree nil         = leaf
  tree (cons x xs) = insert x (tree xs)

  -- Ordered lists

  data OList (lu : Ext A × Ext A) : Set where
    []  : {{l≤u : ext R lu}}  OList lu
    _∷_ : (p : A)
            (let (l , u) = lu)
            {{l≤p : ext R (l , # p)}}
            (ps : OList (# p , u))  OList lu

  -- Flattening a BST

  _++_ : ∀{l m u}
         (xs : OList (l , m))
         (ys : ∀{k} {{k≤m : ext R (k , m)}}  OList (k , u))  OList (l , u)
  (x  xs) ++ ys = x  (xs ++ ys)
  []       ++ ys = ys

  infixr 1 _++_

  flatten : ∀{lu} (t : BST lu)  OList lu
  flatten leaf     = []
  flatten (node p lt rt) = flatten lt ++ (p  flatten rt)

  -- Sorting is flatten ∘ tree

  sort : (xs : List A)  OList ( , )
  sort xs = flatten (tree xs)