COMP 210, Spring 2001
Homework 7 : Map, fold, curry
Due Oct.17 (wed), at start of class;
will also be accepted 19th (fri) at start of class.
You are NOT required to show the template for your programs
(woo-hoo!).
Your functions should still follow the template, though.
And of course, each function should still have a contract and purpose,
and reasonable test cases.
Before you tackle the homework, remind yourself of our
General Advice,
Advice on Homeworks
(in particular:
staple
and
provide
questions),
and the
Grading Guidelines.
Some problems on this homework
use the teachpack
shapes.ss
(located in /home/comp210/Homeworks/Hw07/),
a few bits from previous homework solutions:
-
posns,
-
translate-shape: shape, num, num --> shape
(hw02),
-
draw-shape: shape --> true
(hw02),
-
draw-shapes: list-of-shape --> true
(hw04),
-
circle-tool : number --> circle
(hw04;
given a number,
create a circle at 150,150 and radius proportional to the number),
-
as well as some shapes named
circ1: circle
and
rect1: rectangle.
Do not re-write these provided functions!
To use the teachpack at home, you need to
copy the files
shapes.ss
and
shapes-body.ss
(in ~comp210/Homeworks/Hw07, and then add (just) shapes.ss
as a teachpack).
-
(4pts)
Write the following using
map
and
foldr
(but no explicit recursion):
-
make-circles : list-of-number --> list-of-shape,
which makes a circle out of every number in the input list,
using the teachpack's circle-tool.
-
translate-shapes : list-of-shape, posn --> list-of-shape.
Translate each element of the list by the specified amount.
- max-list,
which takes in a list and returns the largest element.
Note: rather than say this function only takes in
non-empty lists, we'll allow empty lists, and
use negative infinity (#i-inf.0) as the
sentinel value for empty lists.
(This is a convenient value for max-list's code,
but may or may not be a reasonable answer for different problems:
If you are looking for the wealth of
the richest person named
Rumpelstilzkin,
and you get the answer "infinitely in debt", does this mean
there is no such name person,
or were there so-named people who
lost a wager to the tune of "more money than anybody can ever name"?)
-
dot-product,
which takes in two lists of n numbers
(
a1
a2
...
an)
and
(b1
b2
...
bn)
and returns
a1*
b1
+
a2*
b2
+
an*
bn
(for any n >= 0).
(What are some trivial test cases?)
Hint: the built-in map actually can
take
in binary functions and two lists of arguments,
as you wrote separately in the previous hw's map2.
-
(4pts)
-
Write slope@,
which takes in a function f : real --> real,
a number x,
and a positive number e
(the "tolerance", usually small ... whatever "small" means).
It returns an approximation to the slope of f at
the point x,
according to the math formula:
slope@(f,x,e) = (f(x+e) - f(x-e)) / 2e
(Thus, the slope of a horizontal line (constant function) is 0 everywhere,
and of a line at 45 degrees (identity function) is 1 everywhere,
and a curve which is horizontal "for a moment" has
a slope of 0 just at that point (e.g. the top of the St. Louis arch).)
Aside:
Really, we're precisely computing f's average slope,
between x-e and x+e (provided f is continuous)
The hope is,
the function's slope at a particular point is close to its
average nearby slope (where "nearby" means "within e").
A good bet for most functions, but
the wigglier f is, the worse our guess is (for a fixed e);
a few functions wiggle wildly
(like
lambda x . sin(1/x) near 0).
To think about:
How might you decide whether a function is very wiggly,
so that your function might automatically decide to try a smaller e?
This problem does not require any knowledge of calculus --
only the math mentioned here.
If you have had calculus:
What is the diference between this approach of finding
the derivative, vs the approach taken by programs like Mathematica?
(Which is closer to what you spent months learning, in calculus?)
Also, why does the above formula compute precisely
the average slope of f between two points (if f continuous)?
The average of a function between a and b,
is the integral from a to b divided (normalized) by (b-a);
Note that the integral of f' from a to b is f(b)-f(a) --
that's the fundamental theorem of calculus!:
We can determine the average value of f' over an entire interval,
only by knowing
f at the endpoints.)
-
We'll make a curried version of this:
Write the function slope,
which takes in a function f : real --> real,
and returns a function real --> real,
which takes in any point
and returns (an approximation of) the slope of f at that point.
(You may instead call this derivative or d/dx if you like.)
-
(4pts)
Consider the idea of iterating a function:
for instance, if I repeatedly double 3,
I get 6, then 12, then 24, etc.
That is, I take the output of a function,
and again apply the function to that.
Iterating square twice, starting with 5,
yields (square (square 5)) = 625.
If I had a function
remove-max: list --> list,
then iterating that three times starting with
(list 7 18 2 9 3)
means
(remove-max (remove-max (remove-max (list 7 18 2 9 3))))
=
(list 2 3)
In general, iterating some function f 3 times
starting with i means
(f (f (f i))).
-
Write the function iterate,
which takes a function, a natNum,
and an initial input to the function,
and iterates the function that many times.
(e.g. we saw (iterate remove-max 3 (list 7 18 2 9 3)).
(Hint: what template will you base your code on?)
-
Extra credit (1pt):
Write two different versions of iterate,
one which is tail-recursive and one which isn't
(and indicate which is which, of course).
-
Using iterate,
write remove-first-n,
which takes a number n and list,
and returns the list with the first n items
removed.
(Of course, an error would result if the list
had fewer than n items.)
- (extra credit: 2pts)
Be sure to include contracts:
-
Write the function curry,
which takes in any binary function and
returns a curried version of it.
(For instance,
(curry +) returns a function
equivalent to the lecture note's make-adder.)
-
Write the inverse function,
uncurry, which takes in a
curried function of one argument,
and returns a two-argument function.
-
Now write curry3to2, which takes in ternary functions and
returns binary functions (expecting the first two
of the three original arguments).
Use this to write a curried version of foldr,
and define a couple of list functions (e.g. sum, map)
using this curried foldr.