//
// Course: BU CAS CS 520, Fall 2010
// Instructor: Hongwei Xi (hwxi AT cs DOT bu DOT edu)
// Lecture on Tuesday & Thursday, Oct 19 & 21, 2010
//

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

datatype ilist (int) =
  | ilist_nil (0) of ()
    // ilist_nil: () -> ilist(0)
  | {n:nat} ilist_cons (n+1) of (int, ilist(n))
    // ilist_cons: {n:nat} (int, ilist(n) -> ilist (n+1)
// end of [ilist]

extern
fun head {n:int | n > 0} (xs: ilist(n)): int

// val x = head (ilist_nil) // a type error

extern
fun tail {n:int | n > 0} (xs: ilist(n)): ilist(n-1)

(*
val xs = head
  (tail (ilist_cons (1, ilist_nil))) // a type error
*)

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

extern
fun ilist_length {n:nat} (xs: ilist(n)): int(n)

implement
ilist_length (xs) = let
  fun loop {i,j:nat} .<i>.
    (xs: ilist (i), j: int(j)): int(i+j) =
    case+ xs of
    | ilist_cons (_, xs1) => loop (xs1, j+1)
    | ilist_nil () => j
  // end of [loop]
in
  loop (xs, 0)
end // end of [ilist_length]

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

extern
fun ilist_append {m,n:nat}
  (xs: ilist (m), ys: ilist (n)): ilist (m+n)
// end of [ilist_append]

implement
ilist_append (xs, ys) =
  case+ xs of
  | ilist_cons (x, xs1) => ilist_cons (x, ilist_append (xs1, ys))
  | ilist_nil () => ys
// end of [ilist_append]

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

extern
fun ilist_reverse {n:nat}
  (xs: ilist (n)): ilist (n) = "ilist_reverse"
// end of [ilist_reverse]

implement
ilist_reverse (xs) =
  revapp (xs, ilist_nil) where {
  fun revapp {i,j:nat}
    (xs: ilist(i), ys: ilist(j)): ilist(i+j) =
    case+ xs of
    | ilist_cons (x, xs1) => revapp (xs1, ilist_cons (x, ys))
    | ilist_nil () => ys
  // end of [revapp]
} // end of [ilist_reverse]

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

(* end of [ilist.dats] *)