**About the assignments in ICS 141:**
This course teaches not only new concepts but also new ways of thinking.
Learning to think in new ways usually requires practice-- actually *doing*
the new things a few times (or more). The homeworks are your opportunity
to get that practice. Don't just say to yourself, "Let me just
get the answer down and turn it in; I'll learn how to do it later."
Keep working (by yourself, with the instructor or TAs, or with your classmates)
until you can produce the answers on your own, without help.

It's no secret that some of the problems we assign this quarter are the same as we assigned last quarter. It is entirely possible for you to find the answers from someone who took the course before and just copy them down and turn them in. But besides being academically dishonest, it also won't prepare you to do similar problems on the exams, so your course grade will suffer. Give the assignments the time and attention they require, and enjoy stretching your "mental muscles."

**Due date:** This assignment is due on
Monday, January 24, by 3:00 PM. Deposit your assignment in the locking
drop box in room CS 189. The due date is closer than it seems; be sure
to get started this week so you can ask questions in discussion on Friday.

**Summary:** For this assignment you will
become acquainted with running the Scheme interpreter and the basic patterns
of recursive list processing code in Scheme. A few of the problems will
seem familiar to those who took ICS 22 here from me; I apologize for the
repetition but your work back then will pay off now.

**Part I (Readings and review questions):**
Each chapter of Sebesta ends with two sets of exercises, one called "review
questions" and one called "problem set." Each set is numbered
starting from 1, so be careful to verify which set we're asking for
on each assignment.

You should know the answers to the review
questions listed below, but you do not have to turn them in. This list
should help you identify some of the more important concepts in the text.
(On the other hand, don't infer that topics we skip or omit are entirely
*un*important.)

Chapter 1: 1-11, 13, 15-17, 19-25, 27-32. Come back to these questions at the end of the course, as you review for the final.

Chapter 2: 8, 14-17, 21, 26-30, 35-38, 42, 43, 46.

Chapter 14: 1, 4, 6-9, 14.

**Part II:** In Chapter 2 of Sebesta,
answer in one or two brief sentences each of the following questions in
the problem set on page 104: 6, 7, 8, 9, and 14. (Note that these are
questions from the "problem set," not from the "review questions.")

Feel free to try some of the exercises we don't assign, but if you get stuck, ask us before spending too much time on any problem; not all of them address issues that will be important to us.

**Part III:** We cover Scheme in ICS 141
for two main reasons: To illustrate concepts of functional programming,
including higher-order functions, and to give you experience learning a
new language that's significantly different from what you already know.
Learning to think in a new way isn't easy; some frustration is inevitable
as you stretch your mind in new directions. But middle school and high
school students learn this material (see www.schemers.com
and www.cs.rice.edu/CS/PLT/Teaching/),
so you can, too.

**Scheme language details:** Writing textbooks
is hard work, so maybe we can forgive Sebesta missing a few details about
the current status of the Scheme language standard:

-- The two boolean constants are #t
and #f.
NIL
is no longer used, and while the empty list counts as false, it's bad
programming practice to use it that way.

-- Many Scheme implementations allow first
and rest
in place of the historically interesting but hopelessly non-mnemonic car
and cdr.
If yours doesn't, you can just say (define
first car) and (define
rest cdr).

-- Some Scheme implementations allow curly braces or square brackets instead
of parentheses, as a visual aid to matching pairs up. That's not standard;
you should just use parentheses and let your environment do the matching
for you.

-- There are two equivalent styles for defining functions, which I'll
call the prototype form and the lambda form. Sebesta uses the prototype
form, which is shorter and which illustrates what a call might look like:
(define (cube x) (* x x x)).
I prefer the lambda form, which doesn't hide the underlying lambda
expression and which is consistent in form with other uses of define:
(define cube (lambda (x)
(* x x x))).

**Scheme implementations:** The NT machines
in the labs have an implementation of Scheme called EdScheme.

For use at home, you can download a limited-time version of EdScheme for free from www.schemers.com; you can also purchase a copy for about 50% off (see us for details). We also recommend DrScheme, another implementation from Rice University that's available entirely for free on most every platform (www.cs.rice.edu/CS/PLT/packages/drscheme/).

**Problems:** For most of these problems,
we'll ask you to print out the transcript window showing your interaction
with the Scheme interpreter. You'll probably want to produce a separate
transcript for turning in, rather than printing out pages and pages showing
all your experimentation. But don't worry if your transcript contains
a few typos.

**(a)** Get used to the Scheme environment.
Try some expressions like (* 123 456)
and (expt 2 100)
and (/ 3.14159265 2).

Type in some definitions of symbols in the global environment, like (define pi 3.14159265), and then try (/ pi 2).

Type in a function definition like this one:

```
(define fact
; Compute n! (n factorial).
```

(lambda (n) ; 0! is 1 by definition

(cond ; The extra
horizontal space

((<= n 0) 1 ) ; isn't
needed; it just lines

(else (* n (fact (- n 1))))))) ; up the
cond clause parts.

Notice how the environment indents and highlights blocks of code so you don't get the parentheses confused.

Make sure you know how to save your code in
a file and load that file into Scheme for evaluation. EdScheme doesn't
automatically re-evaluate changes you make in your code, any more than Visual
C++ does (you have to recompile there, too).

Try some compound expressions, like (gcd
(fact 100) (expt 2 1000)) and
(fact (fact 5))
and (first (rest '(Huey Dewey Louie))).

What is the value produced by (/ (fact 5) (expt 7 2))? This result is called "exact representation"--it looks unusual to us, but it's useful in further calculations because nothing is lost by rounding off to a decimal representation. On the other hand, evaluate (output-fixed-point (/ (fact 5) (expt 7 2)) 15 10). (The 15 is the total size in characters of the result; the 10 is the number of digits to the right of the decimal point.) The code for output-fixed-point is available on Masterhit, the NT lab server.

What happens when you evaluate (fact (fact 500))?

Play around more with EdScheme, trying other expressions. Experiment with the list operators--cons, first, rest, list, append, null?--until you're comfortable with how they work. You can look at the online help (available under the Help menu or question-mark button) for some more information. To understand what a function does, be sure you understand what kinds of data it expects as its arguments (atoms? lists? numbers?) and what kind of data it returns. The function cons, for example, takes any expression as its first argument and a list as its second argument, and it returns a list.

You don't have to turn anything in for
this part (**III (a)**) of the lab. But of course if you short-change
the time you spend building familiarity, you'll have much more trouble
later on.

**(b)** This function, called Ackerman's
function, grows really fast:

```
(define A
```

(lambda (x y)

(cond ((= x 0) (+ 1 y))

((= y 0) (A (- x 1) 1))

(else (A (- x 1)

(A x (- y 1)))))))

**(b.1) **Type it in and
try it out (with very small arguments). Then print out the Transcript window
showing what you did. (But you don't have to print out results that
show pages and pages of solid digits.)

**(b.2)** Rewrite Ackerman's function
on paper using standard mathematical notation.

**(c)** What's the longest number
you can generate in the Scheme you're using, without running out of
memory and taking no more than 60 seconds of processor time? Generating
the big numbers is one part of the question; counting the digits is another.

**(c.1)** Try using (string-length
(number->string * your-big-number*)).

**(c.2)** Try to approximate it using
the log base 10.

**(c.3)** Try to do it using some tool(s)
other than Scheme (or any programming language).

**(c.4)** Using your wristwatch (or slow,
measured counting), time how long it takes for Scheme to calculate and display
your big number. Now, time how long it takes to calculate the big number
*and then* its length (by nesting the expression to generate the big
number inside the length-calculating expression from part **(c.1)** or
**(c.2)**). You'd expect the second to take longer, but on some
Scheme systems it doesn't. Does it on your system? Why might the generate-and-calculate-length
task take *less* time?

**(c.5)** Type up your answers to these
questions and print a transcript showing what you did. Again, don't
print more than a page or two of solid digits.

**(d)** Write each of the following functions
in Scheme. For each, pay attention to the type of value that's returned:
Is it a list, a single item, a number, a boolean? If you're new to
recursive thinking, it will take you a while to start seeing the patterns;
that's why there are so many exercises (and even this many may not be
enough).

Go back and read what the course reference sheet says about collaboration. It's good to work with your classmates, but remember that the goal is that you be able to write routines like this independently.

`(member? A B)`
returns `#t`
(true) if `A`
occurs in the list `B`,
and `#f`
(false) if it doesn't. (Sebesta solves this in the text, but try it yourself
first.)

`(member? 'a '())`
returns `#f`;

`(member? 'a '(b a t t y))`
returns `#t`;

`(member? '(b (c)) '(a b (b (c)) d
(b (c))))` returns `#t`;

`(member? '(b (c)) '(a b (c)))`
returns `#f`.

`(find-all-evens A)`
takes a list of numbers and returns a list containing all the numbers from
the original list that are even. The predefined predicate `even?`
is useful here.

`(find-all-evens '())`
returns `()`;

`(find-all-evens '(3 9 7))`
returns `()`;

`(find-all-evens '(1 2 3 4 5))`
returns `(2 4)`;

`(find-all-evens '(3 2 7 2 6))`
returns `(2 2 6)`.

`(all-even? A)`
takes a list of numbers and returns `#t`
if they're all even, and `#f`
otherwise.

`(all-even? '())`
returns `#t`;

`(all-even? '(3 5 7 2 6))`
returns `#f`;

`(all-even? '(2 8 0 4 88))`
returns `#t`.

`(count-all-matches A B)`
returns the number of times `A`
occurs in the list `B`.

`(count-all-matches 'a '())`
returns `0`;

`(count-all-matches 'a '(a b a c a
d))` returns `3`;

`(count-all-matches 'a '(a b (a) c
(a d)))` returns `1`;

`(count-all-matches '(a (b)) '(a b
(a (b)) a (b) (a (b)) ((a (b)))))`
returns `2`.

`(subst A B C)`
returns `C`
with all occurrences of `A`
changed to `B`.

`(subst 'x 'y '())`
returns `()`;

`(subst 'a 'b '(a c e))`
returns `(b c e)`;

`(subst 'a 'b '(b c d))`
returns `(b c d)`;

`(subst 'a '(a b) '(a b r a))`
returns `((a b) b r (a b))`;

`(subst '(a b c) 'abc '(w x (a b c)
y (a b c) z))` returns `(w
x abc y abc z)`.

`(first-atom A)`
returns the first atom in the list `A`,
no matter how deeply nested. Use the predefined predicates `pair?`
and` null?`
to test whether something is an atom or not.

`(first-atom '())`
returns `()`;

`(first-atom '(a b c))`
returns `a`;

`(first-atom '(((a b) c)))`
returns `a`;

`(first-atom '( () a b c))`
returns `()`,
which is easy because `(atom? '())`
is `#t`.

`(atomize A)`
returns a list of all the atoms in `A`,
no matter how deeply nested. (Hint: Use the predefined function `(append
L1 L2)` to join the atoms in `(first
A)` with the atoms in `(rest
A)`.)

`(atomize '())`
returns `()`;

`(atomize '(a b c))`
returns `(a b c)`;

`(atomize '((a b) c))`
returns `(a b c)`;

`(atomize '(((a) () (b c)) (d e)))`
returns `(a () b c d e)`.

Again, print out a transcript showing your definitions and some tests indicating that they're right.