CSE341 Midterm, Winter 2007
Name of Student_______________________________________________________________
Unless otherwise noted, you may call any of the functions available in the
standard top-level environment including:
the standard operators (~, +, -, *, /, div, mod, ::, @, ^, o,
not, andalso, orelse, <, >, <=, >=, =, <>)
the numeric function abs
the list functions hd, tl, length, rev
the conversion functions real, trunc, floor, ceil, real, ord, chr, str
the string functions implode, explode, concat, size
the standard tuple functions #1, #2, etc.
You may also call any function that is included as a problem on this exam,
whether or not you correctly solve that problem. You may call the functions
listed below that are part of the file utility.sml that we have been using
(notice that this version of map replaces the standard one):
(* sorts a list with the quicksort algorithm given a comparison function *)
(* and a list of values *)
fun qsort(f, []) = []
| qsort(f, pivot::rest) =
let fun split([], ys, zs) = qsort(f, ys) @ [pivot] @ qsort(f, zs)
| split(x::xs, ys, zs) =
if f(x, pivot) then split(xs, x::ys, zs)
else split(xs, ys, x::zs)
in split(rest, [], [])
end;
(* returns a list of the values m through n *)
infix --;
fun m--n =
if m > n then []
else m::(m + 1--n);
fun map(f, []) = []
| map(f, x::xs) = f(x)::map(f, xs);
fun filter(f, []) = []
| filter(f, x::xs) =
if f(x) then x::filter(f, xs)
else filter(f, xs);
exception illegal_reduce;
fun reduce(f, []) = raise illegal_reduce
| reduce(f, [x]) = x
| reduce(f, x::xs) = f(x, reduce(f, xs));
Unless otherwise specified, you can write your own helper functions, but you
are not allowed to use library functions like List.nth or List.last.
1 ML Expressions 20 _____ 6 Functions 5 _____
2 ML Types 10 _____ 7 Functions 10 _____
3 Scope 10 _____ 8 Datatypes 10 _____
4 Curried Functions 10 _____ 9 Functions 10 _____
5 Functions 5 _____ 10 Functions 10 _____
Total _____
1. ML Expressions, 20 points. For each ML expression in the left-hand column
of the table below, indicate in the right-hand column its value. Be sure to
put any string value inside double-quotations marks ("hello" vs hello).
Assume that the following value has been declared:
val lst = [7--9, 2--5, 3--5, 12--14];
Expression Value
-------------------------------------------------------------------------------
map(hd, map(tl, lst)) _______________________________
map(fn x => reduce(op +, x), tl(lst)) _______________________________
map(fn(x, y) => x + y, [(1, 3), (4, 5)]) _______________________________
reduce(op *, map(length, lst)) _______________________________
filter(fn(x) => x div 4 = 2, 1--15) _______________________________
length(reduce(op @, lst)) _______________________________
map(fn(x) => x * x, map(hd, lst)) _______________________________
map(fn(x) => (x, 2 * x), 1--4) _______________________________
reduce(op +, map(fn(x) => 2 * x - 4, 10--15)) _______________________________
map(fn(x) => 2--x, 3--5) _______________________________
2. ML Types, 10 points. For each ML expression in the left-hand column of the
table below, indicate its type in the right-hand column assuming the
expression was added to the standard top-level environment. Assume that the
following value has been declared:
val lst = [8--12, 17--22, 3--9];
Expression Type
-------------------------------------------------------------------------------
lst _______________________________
(hd(lst), hd(hd(lst))) _______________________________
hd o rev o explode _______________________________
fn x => x::[x] _______________________________
fn (x, y) => ((x + y), x, y) _______________________________
3. Scope, 10 points. Consider the following Java program:
public class Mystery {
public static int x = 8;
public static int y = 3;
public static void one() {
x = x + 10;
y = y + 20;
System.out.println(x);
System.out.println(y);
}
public static void two(int x) {
y = y + 100;
one();
}
public static void three() {
int y = 7;
one();
}
public static void main(String[] args) {
int x = 4;
int y = 6;
one();
two(2);
three();
System.out.println(x);
System.out.println(y);
}
}
(2 points) What sequence of numbers does this program output using the
standard lexical scope rules of Java (comma-separated list is okay)?
(5 points) What sequence of numbers does this program output using dynamic
scope as described in lecture (comma-separated list is okay)?
(3 points) What value is answer bound to after executing the following code?
val x = 3;
fun f(n) =
let val y =
let val y = x + 2
val x = 4
in x + y
end
in x + y + n
end
val x = 1;
val answer = f(8);
4. Curried functions, 10 points. For this problem you may call the function
curry and the curried versions of map, filter and reduce that we used in
homework #3:
(* function to convert a noncurried 2-argument function to a *)
(* curried function. For example, curry op+ returns a curried *)
(* version of the addition operator. *)
fun curry f x y = f(x, y);
(* curried versions of map, filter and reduce *)
fun map2 f [] = []
| map2 f (x::xs) = f(x)::(map2 f xs);
fun filter2 f [] = []
| filter2 f (x::xs) =
if f(x) then x::(filter2 f xs)
else filter2 f xs;
fun reduce2 f [] = raise illegal_reduce
| reduce2 f [x] = x
| reduce2 f (x::xs) = f(x, (reduce2 f xs));
As in homework #3, you may use only val definitions to solve the following
problems. You may not use "fun" or "fn" definitions to define a function.
(3 points) Define a function f1(str) that takes a nonempty string as an
argument and that returns the last character of the string
(3 points) Define a function f2(n) that takes an integer n and that returns
true if and only if n is not a factor of 120
(4 points) Define a function f3(n) that returns a list of the first n
even integers assuming n is greater than 0 (e.g., f3(3) returns [2,4,6])
5. Functions, 5 points. Write a function member(v, lst) that takes a value v
and a list lst as arguments and that returns true if and only if v appears
at least once in lst.
6. Functions, 5 points. Write a function pow2(n) that takes an integer n as an
argument and that returns a list of the first n powers of 2 starting with 1
(2^0). For example, pow2(5) should return [1,2,4,8,16]. Your function must
run in O(n) time, which means that it should require approximately n
multiplications or additions. You may assume that n is not negative.
7. Functions, 10 points. Write a function partitionModN(lst, n) that takes a
list of integers lst and an integer n as arguments and that returns a list
obtained by partioning the list into n segments (possibly empty) using the
mod operator. The result should begin with all values that are 0 in mod n,
followed by the values that are 1 in mod n, followed by the values that are
2 in mod n, and so on, ending in the values that are (n - 1) in mod n. It
does not matter what order the elements appear in within any segment.
partitionModN([8, 7, 4, 3, 1, 5, 14, 2, 19], 4) could return
[8, 4, 1, 5, 14, 2, 7, 3, 19] or
[4, 8, 5, 1, 2, 14, 19, 3, 7] (and several others)
Write your solution to function partitionModN below.
8. Datatypes, 10 points. Recall the datatype we discussed in lecture for
storing binary trees of integers:
datatype intTree = Empty | Node of int * intTree * intTree;
(3 points) Write a function product that takes an intTree and that returns
the product of the values in the tree. Assume that the empty tree has a
product of 1.
(7 points) Write a function sameStructure that takes two intTrees and that
returns true if and only if the trees have the same structure. Two trees
are considered to have the same structure if they have the same number of
nodes and the same pattern of left and right subtrees. It does not matter
what values are stored in the trees in making this determination (only the
structure matters).
Questions 9 and 10 involve what is called a directed graph. A directed graph
is composed of a set of vertices and edges. We'll assume the vertices are
numbered with integers and that the edges are specified as an unordered list of
int * int tuples. For example, consider the following list:
val lst = [(1, 2), (2, 3), (2, 4), (4, 5), (5, 3)];
Each pair of values indicates a directed edge connecting two vertices of the
graph. The pair (1, 2) indicates that there is an edge from vertex 1 to vertex
2. The pair (2, 3) indicates that there is an edge from vertex 2 to vertex 3.
And so on. Below is the resulting graph.
1 ---> 2 ---> 3
| ^
v |
4 ---> 5
Notice that the edges have a specific direction. There is an edge from vertex
1 to vertex 2, but not in the other direction. Although there are no examples
in this graph, it is possible to have a connection in both directions between
a pair of vertices if the list contains both (v1, v2) and (v2, v1).
9. Functions, 10 points. Write a function adjacent(v, lst) that takes a
vertex v and a list of edges lst as arguments and that returns a list of
all vertices that have an edge starting with v. For example, given the
previous definition:
adjacent(1, lst) would return [2]
adjacent(2, lst) would return [3, 4] (any order)
adjacent(3, lst) would return []
adjacent(4, lst) would return [5]
adjacent(5, lst) would return [3]
As indicated above, if there is more than one adjacent vertex, your
function can list them in any order. Write your solution to function
adjacent below.
10. Functions, 10 points. Write a function reachable that takes a vertex and a
list of edges as arguments and that returns a list of all vertices that are
reachable from the given vertex. A vertex is considered reachable if it is
adjacent or if it is reachable from an adjacent vertex. For example, given
the definition above:
reachable(1, lst) would return [2,3,4,5] (any order)
reachable(2, lst) would return [3,4,5] (any order)
reachable(3, lst) would return []
reachable(4, lst) would return [3,5] (any order)
reachable(5, lst) would return [3]
As indicated above, if there is more than one reachable vertex, your
function can list them in any order. Your function must deal with the
possibility of a cycle. For example, if the original graph had included
the connection (3, 4), then the following answers would change:
reachable(3, lst) would return [3,4,5] (any order)
reachable(4, lst) would return [3,4,5] (any order)
reachable(5, lst) would return [3,4,5] (any order)
Notice that a vertex can be reached from itself if there is a sequence of
adjacent vertices that starts and stops at the same vertex. Write your
solution to function reachable below.