University of Virginia, Department of Computer Science
CS655: Programming Languages, Spring 2001

Problem Set 1: Higher-Order Functions Out: 23 January 2001
Due: Thursday, 1 Feburary (in class)


This problem set is intended to make everyone comfortable programming with higher-order functions. After completing this problem set, you should be able to understand any Scheme program, and be able to use higher-order functions to program in powerful and elegant ways.

This problem set uses fairly high pace and doesn't involve producing useful stand-alone programs. If you would prefer a more gradual introduction and get some practice using Scheme to produce useful programs, I recommend trying the 6.001 problem sets referenced in the last section first.

Collaboration Policy
You are required to collaborate on this problem set. Each student has been pseudo-randomly (according to alphabetical order) assigned a problem set partner shown below. You will not be required to work with the same partner again.

Team 1: Yuanfang Cai ("Doris")
Weilin Zhong
Team 2: Brian Clarke
Ronghua Zhang
Team 3: Michael Deighan ("Mike")
Hao Zhang
Team 4: Elisabeth Strunk
Haiyong Wang
Team 5: Michael Tashbook ("Mike")
Christopher Taylor ("Chris")

The goal of your collaboration is not to complete the problem set as quickly as possible (for example by dividing it between the two teammates). It is to make both teammates understand as much as possible. If one partner understands something and the other does not, she should explain it to him until he understands well enough to explain it clearly back to her.

It is up to you whether you decide to work together, or inpendendly at first and then go over your answers together. It is usually a good idea if each partner reads through and thinks about the problems independently before you start working together.

Each problem set pair should turn in exactly one problem set. Both team members will receive the same grade. In cases where one team member does not want to do the problem set, the orphaned team member may decide to work independently (and get her own grade on the problem set), or join another team.

Running Scheme

The easiest way to run Scheme is using M-x run-scheme in emacs. This should work on any of the CS department interactive machines (cobra, viper, etc.)

You can download scheme from
You may use any version of scheme you want, but that is the version I will use to develop the problem sets.

It is strongly recommended that you use an editor such as emacs which automatically balanced parentheses for you.

0. Value of Everything, Cost of Nothing

(Questions numbered "0" are warm-ups. You don't need to turn in answers to 0-numbered questions.)

Predict the value of the following Scheme expressions. Use the Scheme interpreter to check your answers.

a. 7
b. (+ (* 5 11) (* (+ 17 3) (+ 17 (+ 10 3))))
c. ((lambda (f x) (f x x)) + 2)
d. ((lambda (f) (f 2)) (lambda (x) (+ x x)))

The next two are based on a very special function known as the Y-operator. We'll see more about this later, so don't worry if it doesn't make sense now (but do try to guess what they will do and try them in the Scheme interpreter).


((lambda (n)
   ((lambda (f) (f f n))
    (lambda (f k) (if (= k 1) 
		      (* k (f f (- k 1))))))) 


((lambda (n) 
   ((lambda (f) (f f n)) 
    (lambda (f k) (f f k)))) 

1. Mergering

a. Write a Scheme procedure listadder that combines two lists by adding their elements. For example, (listadder '(3 1 3) '(3 4 2)) should produce (6 5 5). (Don't worry about making your procedure work for lists of different length.)

b. Write deeplistadder that works on nested lists also. For example, (deeplistadder '((1 2 (3 4)) 4) '((1 2 (3 4)) 6)) should produce ((2 4 (6 8)) 10).

c. The deeplistadder procedure could be defined using a more general procedure we can call deeplistmerge. Define deeplistmerge so that deeplistadder could be defined as

        (define (deeplistadder list1 list2)
	    (deeplistmerge + list1 list2))

d. Define a function deeplistmaxer that combined the lists by choosing the higher element. For example, (deeplistmaxer '(3 1 3) '(3 4 2)) should be (3 4 3).

e. Try to write the deeplistmerge function using some other programming language you know well.

(1) For the language you choose, is it possible to write deeplistmerge?

(2a) If so, is it harder or easier than it was to do using Scheme? What properties of the languages make it harder or easier?

(2b) If not, is the language you choose a universal programming language? (Reconcile any paradoxes in your answers.)

2. Whiling Away While

a. I. M. Peirative complains that Scheme can't possibly be a useful language, since it does not have a while loop, and everyone knows you can't write any useful programs without having a while loop.

Show I. M. that he is wrong by defining a procedure in scheme that provides the power of a while loop. Using your procedure, I. M. should be able to define factorial using:

(define (factorial n)
  (while (lambda (x) (<= x n))  ;;; the while predicate
	 (lambda (x) (+ x 1))   ;;; the increment function
	 (lambda (ival accum) (* ival accum)) ;;; the loop body
	 1  ;;; initial i value
	 1)) ;;; initial accum value
Your definition should be in the form
(define (while pred inc body val accum) ???).

Alyssa P. Hacker points out that she can use your definition of while to define for so her friend Phor Tran is happy also. She defines for:

   (define (for start end body accum)
     (while (lambda (x) (<= x end))
	    (lambda (x) (+ x 1))

b. Show how factorial can be defined using for.

I. M. is impressed with this, but Pasquale A. Holick claims that while while and for are all good and dandy, but any real programming language has repeat ... until.

c. Show Pasquale that you can provide repeatuntil also. Your definition of repeatuntil should use while, and should not need a recursive call. Pasquale wants to use your definition to define factorial using:

   (define (factorial n)
     (repeatuntil (lambda (x) (> x n))  ;;; the until predicate (stop when it is true)
		  (lambda (x) (+ x 1))   ;;; the increment function
		  (lambda (ival accum) (* ival accum)) ;;; the loop body
		  1  ;;; initial i value
		  1)) ;;; initial accum value
d. Use the power of higher-order functions to invent and define a new control form. Demonstrate that your control form is useful by showing how it can be used to elegantly and concisely express a program.

More Practice

If you want more practice using Scheme, I recommend:

CS 655 University of Virginia
Department of Computer Science
CS 655: Programming Languages
David Evans