3.7 Decisions

To make more useful procedures, we need the actions taken to depend on the input values. For example, we may want a procedure that takes two numbers as inputs and evaluates to the greater of the two inputs. To define such a procedure we need a way of making a decision. The IfExpression expression provides a way of using the result of one expression to select which of two possible expressions to evaluate:

Expression ::$\Rightarrow$ IfExpression
IfExpression ::$\Rightarrow$ (if Expression$_{Predicate}$
Expression$_{Consequent}$
Expression$_{Alternate}$)

The IfExpression replacement has three Expression terms. For clarity, we give each of them names as denoted by the Predicate, Consequent, and Alternate subscripts. To evaluate an IfExpression, first evaluate the predicate expression, Expression$_{Predicate}$. If it evaluates to any non-false value, the value of the IfExpression is the value of Expression$_{Consequent}$, the consequent expression, and the alternate expression is not evaluated at all. If the predicate expression evaluates to false, the value of the IfExpression is the value of Expression$_{Alternate}$, the alternate expression, and the consequent expression is not evaluated at all.

The predicate expression determines which of the two following expressions is evaluated to produce the value of the IfExpression. If the value of the predicate is anything other than |false|, the consequent expression is used. For example, if the predicate evaluates to |true|, to a number, or to a procedure the consequent expression is evaluated.

The if expression is a special form. This means that although it looks syntactically identical to an application (that is, it could be an application of a procedure named if), it is not evaluated as a normal application would be. Instead, we have a special evaluation rule for if expressions. The reason a special evaluation rule is needed is because we do not want all the subexpressions to be evaluated. With the normal application rule, all the subexpressions are evaluated first, and then the procedure resulting from the first subexpression is applied to the values resulting from the others. With the if special form evaluation rule, the predicate expression is always evaluated first and only one of the following subexpressions is evaluated depending on the result of evaluating the predicate expression.

This means an if expression can evaluate to a value even if evaluating one of its subexpressions would produce an error. For example,

(if ( > 3 4) (* + +) 7)

evaluates to 7 even though evaluating the subexpression (* + +) would produce an error. Because of the special evaluation rule for if expressions, the consequent expression is never evaluated.

Example 3.3: Bigger

Now that we have procedures, decisions, and definitions, we can understand the |bigger| procedure from the beginning of the chapter. The definition,

(define (bigger a b) (if ( > a b) a b))

is a condensed procedure definition. It is equivalent to:

(define bigger (lambda (a b) (if ( > a b) a b)))

This defines the name bigger as the value of evaluating the procedure expression (lambda (a b) (if ( > a b) a b)). This is a procedure that takes two inputs, named a and b. Its body is an if expression with predicate expression ( > a b). The predicate expression compares the value that is bound to the first parameter, a, with the value that is bound to the second parameter, b, and evaluates to true if the value of the first parameter is greater, and false otherwise. According to the evaluation rule for an if expression, when the predicate evaluates to any non-false value (in this case, true), the value of the if expression is the value of the consequent expression, a. When the predicate evaluates to false, the value of the if expression is the value of the alternate expression, b. Hence, our bigger procedure takes two numbers as inputs and produces as output the greater of the two inputs.

Exercise 3.7.  Follow the evaluation rules to evaluate the Scheme expression:

(bigger 3 4)

where `bigger is the procedure defined above. (It is very tedious to follow all of the steps (that’s why we normally rely on computers to do it!), but worth doing once to make sure you understand the evaluation rules.)

Exercise 3.8. Define a procedure, xor, that implements the logical ex­clu­sive-or operation. The xor function takes two inputs, and outputs true if exactly one of those outputs has a true value. Otherwise, it outputs false. For example, (xor true true) should evaluate to false and (xor ( \< 3 5) (= 8 8)) should evaluate to true.

Exercise 3.9.  Define a procedure, absvalue, that takes a number as input and produces the absolute value of that number as its output. For example, (absvalue 3) should evaluate to 3 and (absvalue -150) should evaluate to 150.

Exercise 3.10. Define a procedure, bigger-magnitude, that takes two inputs, and outputs the value of the input with the greater magnitude (that is, absolute distance from zero). For example, (bigger-magnitude 5 -7) should evaluate to -7, and (bigger-magnitude 9 -3) should evaluate to 9.

Exercise 3.11.  Define a procedure, biggest, that takes three inputs, and produces as output the maximum value of the three inputs. For example, (biggest 5 7 3) should evaluate to 7. Find at least two different ways to define biggest, one using bigger, and one without using it.