Problems for Section 7.14---foldr and polynomials

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.)


Thomas VanDrunen
Last modified: Fri Nov 18 16:09:14 CST 2016