//
// Course: BU CAS CS 520, Fall 2010
// Instructor: Hongwei Xi (hwxi AT cs DOT bu DOT edu)
// Lecture on Tuesday, Nov 30, 2010
//

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

datatype tree = E of () | B of (tree, tree)

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

(*
//
// HX: Python-style :)
//
extern fun ht (t: tree): int
fun isPerfect (t: tree): bool =
  case+ t of
  | B (tl, tr) => isPerfect (tl) andalso isPerfect (tr) andalso (ht(tl) = ht(tr))
  | E () => true
// end of [isPerfect]
*)

(*
//
// HX: C-style :)
//
fun isPerfect (t: tree): bool = let
  fun aux (t: tree): int =
    case+ t of
    | B (tl, tr) => let
        val hl = aux (tl)
      in
        if hl >= 0 then let
          val hr = aux (tr) in if hl=hr then hl+1 else ~1
        end else ~1
      end // end of [B]
    | E () => 0
in
  aux (t) >= 0
end // end of [isPerfect]
*)

(*
//
// HX: A functional monadic style
//
fun isPerfect
  (t: tree): bool = let
  fun aux (t: tree): Option (int) =
    case+ t of
    | B (tl, tr) => (case+ aux(tl) of
      | Some hl => (case+ aux(tr) of
        | Some hr => if hl=hr then Some (hl+1) else None ()
        | None () => None ()
        )
      | None () => None ()
      ) // end of [B]      
    | E () => Some (0)
in
  case+ aux (t) of | Some _ => true | None () => false
end // end of [isPerfect]
*)

(*
// HX: An example of proper use of exception
*)

fun isPerfect
  (t: tree): bool = let
  exception NotPerfect of ()
  fun aux (t: tree): int =
    case+ t of
    | B (tl, tr) => let
        val hl = aux (tl) and hr = aux (tr)
      in
        if hl = hr then hl + 1 else $raise (NotPerfect)
      end // end of [B]
    | E () => 0
  // end of [aux]
in
  try
    let val _ = aux (t) in true end
  with
    ~NotPerfect () => false
  // end of [try]
end // end of [isPerfect]

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

(* end of [exception.dats] *)