Scheme Programming/Conditionals

In this section we introduce Scheme's conditional expressions. These forms allow us to make choices--something that's been lacking from the simple programs we've seen so far.

Truth values in Scheme
We've already seen the boolean values  ("true") and ("false") in previous examples, as the values of expressions like. Booleans have few procedures ; the most commonly seen is probably , which negates its argument:

In Scheme, booleans are not the only objects with truth values; the convention of Scheme is to consider  to be false and every other Scheme value to be true. A very common idiom in Scheme is for procedures to return some useful value (which is rarely ) on success, and  otherwise. While our procedures will stick to the practice of returning , it's important to be aware of this idiom.

and and or
The  and   forms let us manipulate truth values in familiar ways:

In this basic usage, these forms give us the Boolean AND and OR, respectively, of their two arguments (called tests). This is often perfectly sufficient. The  and   forms, however, are a bit more flexible. For one thing, they can take any number of tests:

An  expression is thus true if all the tests are true, and an  expression is true if at least one of the tests is true.

As mentioned above, we can also have tests that evaluate to things other than  and  :

Since the first test expression evaluates to  and the second to  (which is not , the only Scheme value considered false), this   expression must be true--but why does it evaluate to ? The Scheme convention is that , when all the tests are true, returns the value of the last test;  returns the value of the first true test. In this way, we can return values more useful than without affecting the truth values of our expressions.

Simple Conditionals: if
The simplest conditional in Scheme is the  form. Here are some examples:

Like  and ,   is a special form with its own syntax. Here's the general form:

The first component of an expression is a test expression, which is evaluated first. If its value is true, the value of the second component expression (the consequent) is returned. If the test evaluates to false, on the other hand, we get the value of the third component (the alternative). Let's see how this works in the above examples. In the first, the test expression is just , so the value of the form is the value of the consequent expression, . To evaluate the second example, we first consider the test,. This evaluates to, so we evaluate the alternative   and return its value as the value of the entire   expression.

Using, we can write some useful procedures. A simple example:

Using  and   forms in our test expressions, we can combine several tests:

cond
We can write a great number of useful Scheme programs with . In fact, by chaining together  s, we can write any conditional expression we want. Unfortunately, these expressions get complicated very quickly. When nesting s, it can be difficult to keep track of all the clauses and it may be necessary to write results several times. (For example, in the last exercise, how many cases are there in which  is the answer?)  In these cases, we'd like something more convenient.

For this reason, Scheme provides, an extremely flexible conditional form which allows multi-way choices to be expressed easily. Here's a short example:

In its simplest form,  takes a number of clauses, each of which consists of a test and a result expression. To evaluate a  expression, we evaluate the tests of each clause in turn; if one evaluates to true, returns the value of that clause's result expression, skipping any remaining clauses. A test which is just the word is always true, and thus a  will always "choose" the result of a clause with  as its test. Typically, the last clause of a  is an "else clause".

A simplified version of the form of a  expression is:

where each clause is of the form  or.

Let's step through the evaluation of a simple expression.

To evaluate this expression, we look at the first clause, . The test expression of this clause is, so we evaluate that; since its value is , we skip this clause and go on to the next, . The test of this clause is, which is "always true". We evaluate this clause's result expression,, and return its value, , as the value of the whole  expression. Since this  expression returns   when the first clause's test is true and  otherwise, it's precisely equivalent to the following   form:

Thus, we can replace any  expression with an equivalent. In fact,  is so general that we can use it in place of any other conditional form.