//
// Course: BU CAS CS 520
// Instructor: Hongwei Xi (hwxi AT cs DOT bu DOT edu)
//

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

//
// How to compile:
//   atscc -o fact -O3 fact.dats
//
// How to test:
//   ./fact
//

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

// this function can be applied to a negative number,
// though it should really be undefined on negative numbers
extern fun fact1 (x: int): int

//
// non-tail-recursive implementation
//
implement fact1 (x) =
  if x > 0 then x * fact1 (x-1) else 1
// end of [fact1]

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

extern fun fact1' (x: int): int

//
// tail-recursive implementation
//
implement fact1' (x) = loop (x, 1) where {
  fun loop (x: int, res: int): int =
    if x > 0 then loop (x-1, x * res) else res
  // end of [loop]
} // end of [fact1']

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

// this function can only be applied to a natural nubmer
extern fun fact2 {i:nat} (x: int i): int

implement fact2 (x) =
  if x > 0 then x * fact2 (x-1) else 1
// end of [fact2]

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

implement main () = let
  val n = 10
  val ans1 = fact1 (n)
  val ans1' = fact1' (n)
  val ans2 = fact2 (n)
in
  printf ("fact1 (%i) = %i\n", @(n, ans1));
  printf ("fact1' (%i) = %i\n", @(n, ans1'));
  printf ("fact2 (%i) = %i\n", @(n, ans2));
end // end of [main]

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

(* end of [fact.dats] *)