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

//
// How to compile:
//   atscc-o tally2 tally2.dats
// How to test:
//   ./tally2
//

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

dataprop TALLY (int, int) =
  | TALLYbas (0, 0) of ()
  | {n:nat} {s:int}
    TALLYind (n+1, s+n+1) of TALLY (n, s)
// end of [TALLY]

(* ****** ****** *)
//
// [TALLY] is a total relation
//
extern
prfun TALLYistot {n:nat} (): [r:int] TALLY (n, r)
// end of [TALLYistot]

//
// [TALLY] is a functional relation
//
extern
prfun TALLYisfun {n:nat} {r1,r2:int}
  (pf1: TALLY (n, r1), pf2: TALLY (n, r2)): [r1==r2] void
// end of [TALLYisfun]

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

//
// HX: this style involves proof consumption
//
fun tally2 {n:nat} (n: int n)
  : [s:int] (TALLY (n, s) | int (s)) = let
//
  fun aux {n:nat} {s:int}
    (pf: TALLY (n, s) | n: int n): int s =
    if n = 0 then let
      prval TALLYbas () = pf in 0
    end else let
      prval TALLYind pf1 = pf
      val s1 = aux (pf1 | n-1) in s1 + n
    end // end of [if]
  // end of [aux]
//
  prval pf = TALLYistot (); val s = aux (pf | n)
//
in
  (pf | s)
end // end of [tally2]

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

implement
main () = () where {
  #define N 100
  val (pf | ans) = tally2 (N)
  val () = printf ("sum(1 ... %i) = %i\n", @(N, ans))
} // end [main]

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

(* end of [tally2.dats] *)