(*
// This file is for Assignment 4, BU CAS CS 520, Fall, 2009
//
// Instructor: Hongwei Xi (hwxi AT cs DOT bu DOT edu)
//
*)

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

//
// Here is some code that you may want to study when doing Exercise 1
//

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

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

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

abst@ype T

typedef List =
  {X:type} (X, (T, X) -<cloref> X) -<cloref> X
// end of [List]

val Nil = lam{X:type} (nil:X, cons: (T, X) -<cloref> X) =<cloref> nil
val Cons = lam (x: T, xs: List) =<cloref>
  lam{X:type} (nil:X, cons: (T, X) -<cloref> X) =<cloref> cons (x, xs{X}(nil, cons))
// end of [fun]

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

extern fun List_append (xs: List, ys: List):<> List
implement List_append (xs, ys) = xs {List} (ys, Cons)

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

extern fun List_reverse (xs: List):<> List
implement List_reverse (xs) =
  xs {List} (Nil, lam (_x, _xs) => List_append (_xs, Cons (_x, Nil)))

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

assume T = int

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

typedef int = intptr
val _0 = intptr_of_int 0
val _1 = intptr_of_int 1

fn List_length (xs: List):<> int = xs {int} (_0, lam (_x, _xs) => _xs + _1)

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

fn list_of_List (xs: List): list0 T = let
  typedef X = list0 T
  val nil = list0_nil : X
  val cons = lam (_x: T, _xs: X) =<cloref> list0_cons (_x, _xs)
in
  xs {X} (nil, cons)
end // end of [list_of_List]

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

fn List_print (xs: List): void = let
  val nil = unit ()
  val cons = lam (_x: T, _xs: unit) =<cloref> $effmask_all (print _x; print_newline (); _xs)
  val unit () = xs {unit} (nil, cons)
in
  // nothing
end // end of [List_print]

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

val xs123 = Cons (1, Cons (2, Cons (3, Nil))) : List

val () = begin
  print "length of xs123 = "; print (List_length xs123); print_newline ()
end // end of [val]

val () = print "xs123 =\n"
val () = List_print xs123

val xs321 = List_reverse (xs123)
val () = print "xs321 =\n"
val () = List_print xs321

val xs123123 = List_append (xs123, xs123)
val () = print "xs123123 =\n"
val () = List_print xs123123

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

implement main () = ()

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

(* end of [exercise1.dats] *)