Procedure definitions

As section 2.2 of the textbook explains, a programmer can have Scheme construct a new procedure, not equivalent to any of the built-in ones, by writing a lambda-expression. For instance, Scheme recognizes the expression

(lambda (root)
  (* root root))

as a description of a procedure that, when called, squares its argument. Like any other value, this procedure can be given a name by means of a definition:

;;; square: multiply a given number by itself

;;; John David Stone
;;; Department of Mathematics and Computer Science
;;; Grinnell College
;;; stone@cs.grinnell.edu

;;; created February 13, 1999
last revised March 17, 2000

;;; Given:
;;;   ROOT, an exact number.

;;; Result:
;;;   SQUARED, an exact number.

;;; Preconditions:
;;;   None.

;;; Postcondition:
;;;   SQUARED is the product of ROOT and ROOT.

(define square
  (lambda (root)
    (* root root)))

Such a procedure can be called, just as if it were a built-in procedure:

> (square 12)
144

Exercise 1

One foot is equal to 761/2500 meters (exactly). Define a procedure named feet->meters that takes one argument, a real number representing a length measured in feet, and returns the number that represents the same length as measured in meters. Use this procedure to determine the number of meters in one mile (5280 feet).


Exercise 2

The price of admission to see a first-run movie at the Bijou Theatre is seven dollars for an adult, four for a child. Define a procedure named gross-receipts that takes two arguments, the number of adults and the number of children admitted, and returns the total amount that they paid for admission, in dollars. For instance, if the audience included exactly 112 adults and six children, the procedure should return the sum of 112 times seven and four times six, which is 808:

> (gross-receipts 112 6)
808

Use your procedure to determine the total admission for eighty-two adults and 146 children.


Exercise 3

In a figure-skating competition, judges have observed the competitors' performances and awarded three separate scores to each competitor: one for accuracy, one for style, and one for the difficulty of the chosen routine. Each score is in the range from 0 to 10. The rules of the competition specify that a competitor's three scores are to be combined into a weighted average, in which accuracy counts three times as much as difficulty and style counts twice as much as difficulty. The overall result should be a single number in the range from 0 to 10.

Write a comment in which you describe the nature and purpose of a procedure that takes three arguments -- a competitor's accuracy, style, and difficulty scores -- and returns their weighted average. Then define the procedure that you have described. Next, test your procedure, looking for cases in which the weighted average is computed incorrectly. (If you find any, make corrections in your definition.) Finally, save the procedure and documentation in an appropriately named file.


Booleans and predicates

A Boolean value is a datum that reflects the outcome of a single yes-or-no test. For instance, if one were to ask Scheme to compute whether the empty list has five elements, it would be able to determine that it does not, and it would signal this result by displaying the Boolean value for ``no'' or ``false,'' which is #f. There is only one other Boolean value, the one meaning ``yes'' or ``true,'' which is #t. (These are called ``Boolean values'' in honor of the logician George Boole, who was the first to develop a satisfactory formal theory of them.)

A predicate is a procedure that always returns a Boolean value. A procedure call in which the procedure is a predicate performs some yes-or-no test on its arguments. For instance, the predicate number? -- the question mark is part of the name of the procedure -- takes one argument and returns #t if that argument is a number, #f if it does not. Similarly, the predicate even? takes one argument, which must be an integer, and returns #t if the integer is even and #f if it is odd. The names of most Scheme predicates end with question marks, and I recommend this useful convention even though it is not required by the rules of the programming language.

Here is a selection of ``primitive'' (that is, built-in) Scheme predicates:


Exercise 4

Call each of the predicates on the preceding list twice -- once with an argument that ensures that the value of the procedure call is #t, once with an argument that makes the value #f.


Another useful Boolean procedure is not, which takes one argument and returns #t if the argument is #f and #f if the argument is anything else. For example, one can test whether the square root of 100 is unequal to the absolute value of -12 by giving the command

(not (= (sqrt 100) (abs -12)))

If Scheme says that the value of this expression is #t, then the two numbers are indeed unequal.


Exercise 5

A few lines up, I said that not is a procedure in Scheme. What procedure could you call to find out whether this assertion is true?


Exercise 6

The symbol not is the name of the procedure discussed in the preceding exercise, but the symbol itself, considered as a datum, is not a procedure. Does Scheme agree with this classification? How could one ask Scheme whether the symbol not is a procedure?


Exercise 7

Define a predicate bigger? that takes two real numbers as arguments and returns #t if the absolute value of the first is greater than the absolute value of the second, #f if it is not. Call your procedure twice -- once with arguments that ensure that the value of the procedure call is #t, once with arguments that make the value #f.


This document is available on the World Wide Web as

http://www.cs.grinnell.edu/~stone/courses/scheme/procedure-definitions.xhtml

created September 2, 1997
last revised March 17, 2000

John David Stone (stone@cs.grinnell.edu)