(*
** 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 11, 2009
//

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

#include "BUCASCS320.hats"

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

// a datatype for streams (no memoization)

datatype seq (a:t@ype) =
  Nil(a) of () | Cons(a) of (a, () -<cloref1> seq a)
  
(* ****** ****** *)

typedef int2 = @(int, int)

fun from2_one (i: int, j: int): seq (int2) =
  Cons ( @(i, j), lam () => from2_one (i, j+1) ) 
// end of [from2_one]

fun{a:t@ype} seq_interleave
  (xs1: seq a, xs2: seq a): seq a = case+ xs1 of
  | Cons (x1, fxs1) => Cons (x1, lam () => seq_interleave (xs2, fxs1 ()))
  | Nil () => xs2
// end of [seq_interleave]

fun{a:t@ype} seq_merge 
  (xs1: seq a, xs2: seq a, lte: (a, a) -<cloref1> bool): seq a =
  case+ xs1 of
  | Cons (x1, fxs1) => begin case+ xs2 of
    | Cons (x2, fxs2) => begin
        if x1 \lte x2 then Cons (x1, lam () => seq_merge (fxs1 (), xs2, lte))
                      else Cons (x2, lam () => seq_merge (xs1, fxs2 (), lte))
      end // end of [Cons]
    | Nil () => xs1
    end // end of [Cons]  
  | Nil () => xs2
// end of [seq_merge]

fun lte_int2_int2
  (xy1: int2, xy2: int2): bool = let
  val s1 = xy1.0 + xy1.1; val s2 = xy2.0 + xy2.1
in
  s1 < s2 orelse (s1 <= s2 andalso xy1.0 <= xy2.0)
end (* end of [lte_int2_int2] *) 

fun from2_all
  (i: int, j: int) = let
  val ij = @(i, j)
in
  Cons (ij
  , lam () => let
      val fstrow = from2_one (i, j+1)
      val restbl = from2_all (i+1, j)
    in
      seq_merge<int2> (restbl, fstrow, lam (xy1, xy2) => xy1 \lte_int2_int2 xy2)
    end (* end of [lam] *)
  ) // end of [Cons]
end // end of [from2_all]

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

val theNat2Seq = from2_all (0, 0) // a list of all pairs of natural numbers

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

val () = loop (theNat2Seq, 20) where {
  fun loop (xys: seq int2, n: int): void =
    if n > 0 then let
      val- Cons (xy, fxys) = xys
      val () = printf ("x = %i and y = %i\n", @(xy.0, xy.1))
    in
      loop (fxys (), n-1)
    end // end of [if]
  // end of [loop]  
} // end of [val]

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

implement main () = ()

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

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