For the material covered April 21 (drawn from Sections 7.5 and 7.14),
I'm giving some problems that don't appear in the book.
Enter these in the automated grading system as "7.14.a
"
etc, even though some of these are more related to Section 7.5.
For reference, here is the code for map
,
filter
, and foldr
.
You'll need these in the interpreter to run your code.
fun map(f, []) = [] | map(f, a::rest) = f(a)::map(f, rest); fun filter(f, []) = [] | filter(f, a::rest) = if f(a) then a::filter(f, rest) else filter(f, rest); fun foldr(f, s, []) = s | foldr(f, s, x::rest) = f(x, foldr(f, s, rest));
Remember that to use foldr
to make
function someFunction
, do something like this:
fun someFunction(xx) = foldr(fn(x, y) => ??, ??, xx)
...where the first ??
indicates how to combine
the next item in the list x
with the running result
y
, and the second ??
indicates
what the seed value is.
7.14.a
Use foldr
to write a function catAll
that takes
a list of lists and concatenates them all into a single list.
Here is the non-foldr version:
fun catAll([]) = [] | catAll(xx::rest) = xx @ catAll(rest);
For example:
- catAll([[1,2], [], [3,4,5], [6]]); val it = [1,2,3,4,5,6] : int list
7.14.b
Use foldr
to write a function
numEvens
that takes a list of ints
and counts the number of evens.
Here is a non-foldr version:
fun numEvens([]) = 0 | numEvens(a::rest) = (if a mod 2 = 0 then 1 else 0) + numEvens(rest);
For example:
- numEvens([1,2,3,4,5,6,7]); val it = 3 : int
7.14.c
Recall this new version of the "brute force"
versions of evaluatePoly
that we did in class:
fun evaluatePoly([], x) = 0.0 | evaluatePoly(c::rest, x) = c * pow(x, count(rest)) + evaluatePoly(rest, x); fun evaluatePoly(coeffs, x) = (* evalPolyHelper returns a tuple containing the the value of resulting the sub-polynomial and the current power of x *) let fun evalPolyHelper([]) = (0.0, 1.0) | evalPolyHelper(c::rest) = let val (v, p) = evalPolyHelper(rest) in (c*p + v, x * p) end; in #1(evalPolyHelper(coeffs)) end;
Use foldr
to write a new version;
here is a stub:
fun evaluatePoly(coeffs, x) = #1(foldr(fn(c, (y, px)) => ( ??, ??), (??, ??), coeffs));
The #1
is because the combining function
returns a tuple containing the running result and the current power
of x
. At the end we care only about the
running (now final) result.
(This problem appears in the book as Problem 7.B in Section 7.14,
which you can see for a fuller explanation if necessary.)
Don't confuse evaluatePoly
with the
unrelated function evaluatePohly
.
7.14.d
We have seen two versions of scale
,
a function that takes a list and a factor and scales each element in
the list by the given factor.
Here is the original version:
fun scale(f, []) = [] | scale(f, x::rest) = x * f :: scale(f, rest);
Here is a version that uses map
:
fun scale(f, xx) = map (fn (x) => f * x, xx);
However, this also can be written using foldr
.
Finish the following stub:
fun scale(f, xx) = foldr(fn(x, y) => ??, ??, xx);
Hint: In the anonymous function passed to foldr
the parameter y
is a list.
(A similar problem appears as 7.5.5 in the book.)
7.14.e
When you compare the foldr
version of
scale
to the map
version of
scale
, it suggests that foldr
is
a more primitive/basic/general operation than map
.
In fact, you can rewrite map
using foldr
.
Finish the following stub:
fun map(f, xx) = foldr(fn(x,y) => ??, ??, xx);
(A similar problem appears as 7.5.7 in the book.)