```(*
** 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: Wednesday, June 10, 2009
//

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

#include "BUCASCS320.hats"

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

// Part I: computing primes based on lazy evaluation

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

// exception StreamSubscript of () // defined in BUCASCS320.hats

val theNaturalNumberStream : stream int = from (0) where {
fun from (n:int):<!laz> stream int = \$delay (stream_cons (n, from (n+1)))
} // end of [val]

// stream_car
fun{a:t@ype} stream_car
(s: stream a):<!laz> a = case+ !s of
| stream_cons (x, _) => x
| stream_nil () => \$raise StreamSubscript ()
// end of [stream_car]

// stream_cdr
fun{a:t@ype} stream_cdr
(s: stream a):<!laz> stream a = case+ !s of
| stream_cons (_, s1) => s1
| stream_nil () => \$raise StreamSubscript ()
// end of [stream_cdr]

#define car stream_car
#define cdr stream_cdr

fun{a:t@ype} stream_nth
(s: stream a, n: int):<!laz> a = case+ !s of
| stream_cons (x, s1) => if n = 0 then x else stream_nth (s1, n-1)
| stream_nil () => \$raise StreamSubscript ()
// end of [stream_nth]

val n1000 = stream_nth (theNaturalNumberStream, 1000)
val () = printf ("n1000 = %i\n", @(n1000))

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

fun sieve (s: stream int):<!laz> stream int = \$delay (let
val- stream_cons (p1, s1) = !s
val s1 = stream_filter_cloref<int> (s1, lam x => x mod p1 <> 0)
in
stream_cons (p1, sieve (s1))
end) // end of [sieve]

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

val thePrimeNumberStream = sieve (cdr (cdr theNaturalNumberStream))

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

fn prime_nth_get (n: int) = stream_nth (thePrimeNumberStream, n-1)

val p5 = stream_nth (thePrimeNumberStream, 5-1)
val () = printf ("p5 = %i\n", @(prime_nth_get 5))
val () = printf ("p100 = %i\n", @(prime_nth_get 100))
val () = printf ("p1000 = %i\n", @(prime_nth_get 1000))
val () = printf ("p5000 = %i", @(prime_nth_get 5000))
val () = print_newline ()
val () = print ("Testing memoization: no pause shoule be experienced!")
val () = print_newline ()
val () = printf ("p5000 = %i", @(prime_nth_get 5000))
val () = print_newline ()
// val () = printf ("p10000 = %i\n", @(prime_nth_get 10000))

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

// Part II: line count based on lazy evaluation

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

fun file_line_count (inp: FILEref): int = let
val cs = char_stream_make_file (inp)
fun loop (cs: stream char, cnt: int): int =
case !cs of
| stream_cons (c, cs) =>
(if c = '\n' then loop (cs, cnt+1) else loop (cs, cnt))
| stream_nil () => cnt
// end of [loop]
in
loop (cs, 0)
end // end of [file_line_count]

(*

implement main (argc, argv) = let
val inp = (
if argc >= 2 then open_file (argv.[1], file_mode_r) else stdin_ref
) : FILEref
val cnt = file_line_count (inp)
in
printf ("The number of lines is [%i]\n", @(cnt))
end (* end of [main] *)

*)

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

// Part III: computer Pi based on lazy evaluation and Euler's transform

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

// pi/4 = 1/1 - 1/3 + 1/5 - 1/7 + ...

val thePiStream =
helper (0.0(*sum*), 1(*sign*), 1.0(*denom*)) where {
fun helper
(sum: double, sgn: int, denom: double)
:<!laz> stream double = \$delay (
if sgn > 0 then let
val sum1 = sum + 4.0 / denom in
stream_cons {double} (sum1, helper (sum1, ~1, denom + 2.0))
end else let // sgn = ~1
val sum1 = sum - 4.0 / denom in
stream_cons {double} (sum1, helper (sum1,  1, denom + 2.0))
end // end of [if]
) // end of [helper]
} (* end of [val] *)

local

#define :: stream_cons
#define nil stream_nil

in // in of [local]

fun euler_trans
(ss0: stream double):<!laz> stream double = \$delay (let
val- s0 :: ss1 = !ss0
val- s1 :: ss2 = !ss1
val- s2 :: ss3 = !ss2
val s01 = s0 - s1 and s21 = s2 - s1
in
(s2 - s21 * s21 / (s01 + s21)) :: euler_trans ss1
end : stream_con double
) // end of [euler_trans]

end // end of [local]

val thePiStream1 = euler_trans (thePiStream)

val sum = stream_nth (thePiStream, 100)
val () = printf ("thePiStream_100 = %.8f\n", @(sum))

val sum = stream_nth (thePiStream1, 100)
val () = printf ("thePiStream1_100 = %.8f\n", @(sum))

(*
fun euler_trans_many
(ss: stream double, n: int):<!laz> stream double =
if n > 0 then let
val ss = euler_trans (ss) in euler_trans_many (ss, n-1)
end else ss
// end of [euler_trans_many]
*)

fun euler_trans_tableau
(ss: stream double):<!laz> stream (stream double) =
\$delay (stream_cons (ss, euler_trans_tableau (euler_trans ss)))
// end of [euler_trans_tableau]

val thePiStreamDiag =
stream_map_fun<stream double><double>
(euler_trans_tableau thePiStream, stream_car)
// end of [thePiStreamDiag]

val () = print "thePiStreamDiag:\n"
val sum = stream_nth (thePiStreamDiag, 0)
val () = printf ("thePiStreamDiag_0 = %.10f\n", @(sum))
val sum = stream_nth (thePiStreamDiag, 1)
val () = printf ("thePiStreamDiag_1 = %.10f\n", @(sum))
val sum = stream_nth (thePiStreamDiag, 2)
val () = printf ("thePiStreamDiag_2 = %.10f\n", @(sum))
val sum = stream_nth (thePiStreamDiag, 3)
val () = printf ("thePiStreamDiag_3 = %.10f\n", @(sum))
val sum = stream_nth (thePiStreamDiag, 4)
val () = printf ("thePiStreamDiag_4 = %.10f\n", @(sum))
val sum = stream_nth (thePiStreamDiag, 5)
val () = printf ("thePiStreamDiag_5 = %.10f\n", @(sum))
val sum = stream_nth (thePiStreamDiag, 6)
val () = printf ("thePiStreamDiag_6 = %.10f\n", @(sum))
val sum = stream_nth (thePiStreamDiag, 7)
val () = printf ("thePiStreamDiag_7 = %.10f\n", @(sum))
val sum = stream_nth (thePiStreamDiag, 8)
val () = printf ("thePiStreamDiag_8 = %.10f\n", @(sum))
(*
val sum = stream_nth (thePiStreamDiag, 9)
val () = printf ("thePiStreamDiag_9 = %.10f\n", @(sum))
*)

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

implement main () = ()

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

(* end of [code-2009-06-10.dats] *)
```