Building Abstractions with Procedures
1.1 The Elements of Programming
1.1.6 Conditional Expressions and Predicates
e expressive power of the class of procedures that we can define at this point is very limited, because we have no way to make tests and to perform different operations depending on the result of a test. For instance, we cannot define a procedure that computes the absolute value of a number by testing whether the number is positive, negative, or zero and taking different actions in the different cases according to the rule
|x | =
x if x > 0, 0 if x = 0,
−x if x < 0.
is construct is called a case analysis, and there is a special form in Lisp for notating such a case analysis. It is calledcond(which stands for
“conditional”), and it is used as follows:
(define (abs x) (cond ((> x 0) x)
((= x 0) 0) ((< x 0) (- x))))
e general form of a conditional expression is
16InChapter 3we will introduce stream processing, which is a way of handling appar-ently “infinite” data structures by incorporating a limited form of normal-order evalu-ation. InSection 4.2we will modify the Scheme interpreter to produce a normal-order variant of Scheme.
(cond (⟨p1⟩ ⟨e1⟩) (⟨p2⟩ ⟨e2⟩) . . .
(⟨pn⟩ ⟨en⟩))
consisting of the symbol condfollowed by parenthesized pairs of ex-pressions
(⟨p⟩ ⟨e⟩)
called clauses. e first expression in each pair is a predicate—that is, an expression whose value is interpreted as either true or false.17
Conditional expressions are evaluated as follows. e predicate⟨p1⟩ is evaluated first. If its value is false, then⟨p2⟩ is evaluated. If ⟨p2⟩’s value is also false, then⟨p3⟩ is evaluated. is process continues until a predicate is found whose value is true, in which case the interpreter returns the value of the corresponding consequent expression⟨e⟩ of the clause as the value of the conditional expression. If none of the⟨p⟩’s is found to be true, the value of thecondis undefined.
e word predicate is used for procedures that return true or false, as well as for expressions that evaluate to true or false. e absolute-value procedureabsmakes use of the primitive predicates>,<, and=.18
ese take two numbers as arguments and test whether the first number is, respectively, greater than, less than, or equal to the second number, returning true or false accordingly.
Another way to write the absolute-value procedure is
17“Interpreted as either true or false” means this: In Scheme, there are two distin-guished values that are denoted by the constants#tand#f. When the interpreter checks a predicate’s value, it interprets#fas false. Any other value is treated as true. (us, providing#tis logically unnecessary, but it is convenient.) In this book we will use namestrueandfalse, which are associated with the values#tand#frespectively.
18absalso uses the “minus” operator-, which, when used with a single operand, as in(- x), indicates negation.
(define (abs x)
(cond ((< x 0) (- x)) (else x)))
which could be expressed in English as “If x is less than zero return−x;
otherwise return x.”elseis a special symbol that can be used in place of the⟨p⟩ in the final clause of acond. is causes thecondto return as its value the value of the corresponding⟨e⟩ whenever all previous clauses have been bypassed. In fact, any expression that always evaluates to a true value could be used as the⟨p⟩ here.
Here is yet another way to write the absolute-value procedure:
(define (abs x) (if (< x 0)
(- x) x))
is uses the special formif, a restricted type of conditional that can be used when there are precisely two cases in the case analysis. e general form of anifexpression is
(if ⟨predicate⟩ ⟨consequent⟩ ⟨alternative⟩)
To evaluate anifexpression, the interpreter starts by evaluating the
⟨predicate⟩ part of the expression. If the ⟨predicate⟩ evaluates to a true value, the interpreter then evaluates the⟨consequent⟩ and returns its value. Otherwise it evaluates the⟨alternative⟩ and returns its value.19
In addition to primitive predicates such as<,=, and>, there are log-ical composition operations, which enable us to construct compound
19A minor difference betweenifandcondis that the⟨e⟩ part of eachcondclause may be a sequence of expressions. If the corresponding⟨p⟩ is found to be true, the expres-sions⟨e⟩ are evaluated in sequence and the value of the final expression in the sequence is returned as the value of thecond. In anifexpression, however, the⟨consequent⟩ and
⟨alternative⟩ must be single expressions.
predicates. e three most frequently used are these:
• (and ⟨e1⟩ . . . ⟨en⟩)
e interpreter evaluates the expressions⟨e⟩ one at a time, in le-to-right order. If any⟨e⟩ evaluates to false, the value of theand expression is false, and the rest of the⟨e⟩’s are not evaluated. If all⟨e⟩’s evaluate to true values, the value of theandexpression is the value of the last one.
• (or ⟨e1⟩ . . . ⟨en⟩)
e interpreter evaluates the expressions⟨e⟩ one at a time, in le-to-right order. If any⟨e⟩ evaluates to a true value, that value is returned as the value of the or expression, and the rest of the
⟨e⟩’s are not evaluated. If all ⟨e⟩’s evaluate to false, the value of theorexpression is false.
• (not ⟨e⟩)
e value of a not expression is true when the expression ⟨e⟩
evaluates to false, and false otherwise.
Notice thatandandorare special forms, not procedures, because the subexpressions are not necessarily all evaluated.notis an ordinary pro-cedure.
As an example of how these are used, the condition that a number x be in the range 5< x < 10 may be expressed as
(and (> x 5) (< x 10))
As another example, we can define a predicate to test whether one num-ber is greater than or equal to another as
(define (>= x y) (or (> x y) (= x y)))
or alternatively as
(define (>= x y) (not (< x y)))
Exercise 1.1:Below is a sequence of expressions. What is the result printed by the interpreter in response to each ex-pression? Assume that the sequence is to be evaluated in the order in which it is presented.
10
(+ 5 3 4) (- 9 1) (/ 6 2)
(+ (* 2 4) (- 4 6)) (define a 3)
(define b (+ a 1)) (+ a b (* a b)) (= a b)
(if (and (> b a) (< b (* a b))) b
a)
(cond ((= a 4) 6)
((= b 4) (+ 6 7 a)) (else 25))
(+ 2 (if (> b a) b a))
(* (cond ((> a b) a) ((< a b) b) (else -1)) (+ a 1))
Exercise 1.2:Translate the following expression into prefix form:
5 + 4 + (2− (3 − (6 +45))) 3(6− 2)(2 − 7) .
Exercise 1.3:Define a procedure that takes three numbers as arguments and returns the sum of the squares of the two larger numbers.
Exercise 1.4:Observe that our model of evaluation allows for combinations whose operators are compound expres-sions. Use this observation to describe the behavior of the following procedure:
(define (a-plus-abs-b a b) ((if (> b 0) + -) a b))
Exercise 1.5:Ben Bitdiddle has invented a test to determine whether the interpreter he is faced with is using applicative-order evaluation or normal-applicative-order evaluation. He defines the following two procedures:
(define (p) (p)) (define (test x y)
(if (= x 0) 0 y))
en he evaluates the expression
(test 0 (p))
What behavior will Ben observe with an interpreter that uses applicative-order evaluation? What behavior will he observe with an interpreter that uses normal-order evalu-ation? Explain your answer. (Assume that the evaluation
rule for the special formif is the same whether the in-terpreter is using normal or applicative order: e predi-cate expression is evaluated first, and the result determines whether to evaluate the consequent or the alternative ex-pression.)