(*
** Course: Concepts of Programming Languages (BU CAS CS 320)
** Semester: Summer I, 2009
** Instructor: Hongwei Xi (hwxi AT cs DOT bu DOT edu)
*)

//
// Author: Hongwei Xi (hwxi AT cs DOT bu DOT edu)
// Time: May 29, 2009
//

(* ****** ****** *)

#include "BUCASCS320.hats"

(* ****** ****** *)

datatype bintree =
  | E of ()
  | B of (bintree, int, bintree)

fun bintree_size (t: bintree): int =
  case+ t of
  | B (t1, _, t2) => 1 + bintree_size t1 + bintree_size t2
  | E () => 0
// end of [bintree_size]

fun bintree_height (t: bintree): int =
  case+ t of
  | B (t1, _, t2) => 1 + max (bintree_height t1, bintree_height t2)
  | E () => 0
// end of [bintree_height]

(* ****** ****** *)

// search on a binary search
fun bst_search (t: bintree, k0: int): bool =
  case+ t of
  | B (t1, k, t2) =>
     if k0 < k then bst_search (t1, k0)
     else if k0 > k then bst_search (t2, k0)
     else true // k0 = k
  | E () => false
// end of [bst_search]

// insertion on a binary search tree
fun bst_insert (t: bintree, k0: int): bintree =
  case+ t of
  | B (t1, k, t2) => begin
     if k0 <= k then B (bst_insert (t1, k0), k, t2)
                else B (t1, k, bst_insert (t2, k0))
    end // end of [B]
  | E () => B (E (), k0, E ())
// end of [bst_insert]

// root insertion on a binary search tree
fun bst_insertRT (t: bintree, k0: int): bintree =
  case+ t of
  | B (t1, k, t2) when k0 <= k => let
      val t1_new = bst_insertRT (t1, k0)
      val- B (t11_new, k0, t12_new) = t1_new
    in
      B (t11_new, k0, B (t12_new, k, t2))
    end // end of [B when ...]  
  | B (t1, k, t2) (* k0 > k *) => let
      val t2_new = bst_insertRT (t2, k0)
      val- B (t21_new, k0, t22_new) = t2_new
    in
      B (B (t1, k, t21_new), k0, t22_new)
    end // end of [B when ...]  
  | E () => B (E (), k0, E ())
// end of [bst_insertRT]

(* ****** ****** *)

// Braun trees

datatype tree (a:t@ype) =
  | Lf(a) of ()
  | Br(a) of (a(*elt*), tree a(*left*), tree a(*right*))

exception Subscript of ()

fun{a:t@ype} subscript (t: tree a, k: int): a =
  case+ t of
  | Br (v, t1, t2) =>
     if k = 1 then v
     else if k mod 2 = 0
          then subscript (t1, k / 2)
          else subscript (t2, k / 2)
  | Lf () => $raise Subscript ()
// end of [subscript]

fun{a:t@ype}
  update (t: tree a, k: int, w: a): tree a =
  case+ t of
  | Br (v, t1, t2) =>
     if k = 1 then Br (w, t1, t2)
     else if k mod 2 = 0
          then Br (v, update (t1, k / 2, w), t2)
          else Br (v, t1, update (t2, k / 2, w))
  | Lf () => $raise Subscript ()
// end of [update]

fun{a:t@ype} brauntree_size (t: tree a): int =
  case+ t of
  | Br (_, t1, t2) => 1 + brauntree_size (t1) + brauntree_size (t2)
  | Lf () => 0
// end of [brauntree_size]

(* ****** ****** *)

(* end of [code-2009-05-29.dats] *)