For the material covered today (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.)