(* ** Course: Concepts of Programming Languages (BU CAS CS 320) ** Semester: Summer I, 2009 ** Instructor: Hongwei Xi (hwxi AT cs DOT bu DOT edu) *) // // Assignment three (Due: Monday, June 8, 2009) // // Total points: 180 points // (* ****** ****** *) staload "assignment3.sats" (* ****** ****** *) (* // assgn3ex1: 30 points The following declaration introduces a datatype mylist(a) for representing lists whose elements are of type a: datatype mylist (a:t@ype) = | Nil (a) | Cons (a) of (a, mylist a) | Append of (mylist a, mylist a) | Reverse of mylist a The list append and reverse functions can be implemented as follows: fun append {a:t@ype} (xs: mylist a, ys: mylist a) = Append (xs, ys) fun reverse {a:t@ype} (xs: mylist a) = Reverse xs In other words, both [append] and [reverse] are O(1)-time functions, that is, they take constant time to finish. Please implement the following functions: fun{a:t@ype} mylist_length (xs: mylist): int fun{a:t@ype} mylist_is_empty (xs: mylist a): bool fun{a:t@ype} mylist_nth (xs: mylist a, n: int): a fun{a:t@ype} mylist_to_list0 (xs: mylist a): list0 a Note that nth(xs, i) returns the i_th element in the list represented by xs for 0 <= i < n, where n is the length of xs. The meaning of all other functions should be obvious. \end{exercise} *) implement{a} mylist_length (xs) = aux (xs) where { fun aux (xs0: mylist a): int = case+ xs0 of | Nil () => 0 | Cons (_, xs) => 1 + aux (xs) | Append (xs1, xs2) => aux (xs1) + aux (xs2) | Reverse xs => aux (xs) } // end of [mylist_length] implement{a} mylist_is_empty (xs) = aux (xs) where { fun aux (xs0: mylist a): bool = case+ xs of | Nil () => true | Cons _ => false | Append (xs1, xs2) => (aux xs1) andalso (aux xs2) | Reverse xs => aux xs } // end of [mylist_is_empty] implement{a} mylist_nth (xs, n) = let val n = int1_of_int (n) in if n >= 0 then (try aux (xs, n) with ~NotFound _ => $raise Subscript (): a ) else $raise Subscript (): a end where { exception NotFound of Nat // n is assumed to be a natural number fun aux (xs0: mylist a, n: Nat): a = case+ xs0 of | Nil () => $raise NotFound (n) | Cons (x, xs) => if n = 0 then x else aux (xs, n-1) | Append (xs1, xs2) => ( try aux (xs1, n) with ~NotFound n => aux (xs2, n) ) // end of [Append] | Reverse (xs) => let val nxs = int1_of_int (mylist_length xs) in if n < nxs then aux (xs, nxs-1-n) else $raise NotFound (n-nxs) end // end of [Reverse] // end of [aux] } (* end of [mylist_nth] *) implement{a} mylist_to_list0 (xs) = aux (xs) where { fun aux (xs0: mylist a): list0 a = case+ xs0 of | Nil () => list0_nil () | Cons (x, xs) => list0_cons (x, aux xs) | Append (xs1, xs2) => aux xs1 + aux xs2 | Reverse xs => list0_reverse (aux xs) } (* end of [mylist_to_list0] *) (* ****** ****** *) // include "assgn3ex2_solu.dats" (* ****** ****** *) (* // assgn3ex3: 70 points \begin{exercise} (70 points) Given a sequence $s$ consisting of $n$ elements $a_1,\ldots,a_n$, we represent $s$ as follows. \begin{itemize} \item If $n=0$, that is, $s$ is empty, we use $\exp{Empty}$ to represent $s$; \item If $n=2k$ for some $k>0$, we use $\exp{Even (xs)}$ to represent $s$, where $\exp{xs}$ represents the following sequence of pairs; $$(a_1, a_2), \ldots, (a_{n-1}, a_n)$$ \item If $n=2k+1$ for some $k\geq 0$, we use $\exp{Odd (x, xs)}$ to represent $s$, where $x$ represents $a_1$ and $xs$ represents the following sequence of pairs. $$(a_2, a_3), \ldots, (a_{n-1}, a_n)$$ \end{itemize} We use the name {\em random-access list} for such a representation of $l$. The following datatype $\exp{'a~ralist}$ is declared for this kind of representation of list: \begin{verbatim} datatype 'a pair = S of 'a | P of 'a pair * 'a pair datatype 'a ralist = Emp | Evn of 'a ralist | Odd of 'a pair * 'a ralist \end{verbatim} Please implement the following operations on random-access lists. All the implementations should be of $O(\log n)$-time complexity in order to receive full credit. \begin{enumerate} \item (10 points) Given an element $\exp{x}$ and a random-access list $\exp{xs}$, $\exp{racons (x, xs)}$ generates a random-access list whose head and tail are $\exp{x}$ and $\exp{xs}$, respectively. \item (10 points) Given a nonempty random-access list $\exp{xs}$, $\exp{rauncons (xs)}$ return a pair consisting of the head and tail of $\exp{xs}$. \item (20 points) Given a number $\exp{n}$ and a random-access list $\exp{xs}$, $\exp{ralookup (n, xs)}$ returns the $\exp{n}$th element (counting starts with $0$) in $\exp{xs}$ or issues an error if the length of the random-access list is less than or equal to $\exp{n}$. \item (30 points) Given a number $\exp{n}$ and a random-access list $\exp{xs}$, $\exp{raupdate (xs, n, x)}$ updates the nth element (counting starts with $0$) in $\exp{xs}$ with $\exp{x}$ or issues an error if the length of the random-access list is less than or equal to $\exp{n}$. This one is a bit challenging, and the solution may involve the feature of higher-order function. \end{enumerate} The types of these functions are given below: \begin{verbatim} fun{a:t@ype} racons (x: pair a, xs: ralist a): ralist a fun{a:t@ype} rauncons (xs: ralist a): @(pair a, ralist a) fun{a:t@ype] ralookup (xs: ralist a, i: int): pair a fun{a:t@ype} raupdate (xs: ralist a, i: int, x: pair a): ralist a \end{verbatim} \end{exercise} *) // 10 points // fun{a:t@ype} racons (x: pair a, xs: ralist a): ralist a implement{a} racons (x, xs) = cons (x, xs) where { fun cons (x: pair a, xs: ralist a): ralist a = case+ xs of | Emp () => Odd (x, Emp) | Evn xxs => Odd (x, xxs) | Odd (x1, xxs) => Evn (cons (P (x, x1), xxs)) } // end of [racons] // 10 points // fun{a:t@ype} rauncons (xs: ralist a): @(pair a, ralist a) implement{a} rauncons (xs) = uncons (xs) where { fun uncons (xs: ralist a): @(pair a, ralist a) = case+ xs of | Emp () => $raise Empty () | Evn (xxs) => let val (xx, xxs) = uncons (xxs); val- P (x, x1) = xx in (x, Odd (x1, xxs)) end // end of [Evn] | Odd (x, xxs) => (x, Evn xxs) } // end of [rauncons] // 20 points // fun{a:t@ype} ralookup (xs: ralist a, i: int): pair a implement{a} ralookup (xs, i) = let // [i] is assumed to be a natural number fun lookup (xs: ralist a, i: int): pair a = case+ xs of | Emp () => $raise Subscript () | Evn (xxs) => let val i2 = i / 2; val- P(x, x1) = lookup (xxs, i2) in if i = i2 + i2 then x else x1 end (* end of [Evn] *) | Odd (x, xxs) => if i = 0 then x else let val i = i - 1; val i2 = i / 2; val- P (x, x1) = lookup (xxs, i2) in if i = i2 + i2 then x else x1 end (* end of [Odd] *) // end of [lookup] in if i >= 0 then lookup (xs, i) else $raise Subscript (): pair a end (* end of [ralookup] *) // 30 points // fun{a:t@ype} raupdate (xs: ralist a, i: int, x: pair a): ralist a implement{a} raupdate (xs: ralist a, i: int, x: pair a): ralist a = let // [i] is assumed to be a natural number fun fupdate (xs: ralist a, i: int, f: pair a - pair a): ralist a = case+ xs of | Emp () => $raise Subscript () | Evn (xxs) => let val i2 = i / 2 val f_new = lam (xx: pair a): pair a = let val- P (x0, x1) = xx in if i = i2+i2 then P (f x0, x1) else P (x0, f x1) end // end of [val] in Evn (fupdate (xxs, i2, f_new)) end (* end of [Evn] *) | Odd (x, xxs) => if i = 0 then Odd (f x, xxs) else let val i = i - 1; val i2 = i / 2 val f_new = lam (xx: pair a): pair a = let val- P (x0, x1) = xx in if i = i2+i2 then P (f x0, x1) else P (x0, f x1) end // end of [val] in Odd (x, fupdate (xxs, i2, f_new)) end (* end of [Odd] *) (* end of [fupdate] *) in if i >= 0 then fupdate (xs, i, lam _ => x) else $raise Subscript (): ralist a end (* end of [raupdate] *) (* ****** ****** *) (* end of [assignment3_solu.dats] *)