Control Structures
if
Expressions
The if
special form allows us to evaluate one of two expressions based on a predicate. It takes in two required arguments and an optional third argument:
(if <predicate> <if-true> [if-false])
The first operand is what's known as a predicate expression in Scheme, an expression whose value is interpreted as either #t
or #f
.
The rules for evaluating an if
special form expression are as follows:
- Evaluate
<predicate>
. - If
<predicate>
evaluates to a truth-y value, evaluate and return the value if the expression<if-true>
. Otherwise, evaluate and return the value of[if-false]
if it is provided.
Can you see why this expression is a special form? Compare the rules between a regular call expression and an if
expression. What is the difference?
Step 2 of evaluating call expressions requires evaluating all of the operands in order. However, an
if
expression will only evaluate two of its operands, the conditional expression and either<true-result>
or<false-result>
. Because we don't evaluate all the operands in anif
expression, it is a special form.
Let's compare a Scheme if
expression with a Python if
statement:
Scheme | Python |
---|---|
|
|
Although the code may look the same, what happens when each block of code is evaluated is actually very different. Specifically, the Scheme expression, given that it is an expression, evaluates to some value. However, the Python if
statement simply directs the flow of the program.
Another difference between the two is that it's possible to add more lines of code into the suites of the Python if
statement, while a Scheme if
expression expects just a single expression for each of the true result and the false result.
One final difference is that in Scheme, you cannot write elif
cases. If you want to have multiple cases using the if
expression, you would need multiple branched if
expressions:
Scheme | Python |
---|---|
|
|
cond
Expressions
Using nested if
expressions doesn't seem like a very practical way to take care of multiple cases. Instead, we can use the cond
special form, a general conditional expression similar to a multi-clause if/elif/else conditional expression in Python. cond
takes in an arbitrary number of arguments known as clauses. A clause is written as a list containing two expressions: (<p> <e>)
.
(cond
(<p1> <e1>)
(<p2> <e2>)
...
(<pn> <en>)
[(else <else-expression>)])
The first expression in each clause is a predicate. The second expression in the clause is the return expression corresponding to its predicate. The optional else
clause has no predicate.
The rules of evaluation are as follows:
- Evaluate the predicates
<p1>
,<p2>
, ...,<pn>
in order until you reach one that evaluates to a truth-y value. - If you reach a predicate that evaluates to a truth-y value, evaluate and return the corresponding expression in the clause.
- If none of the predicates are truth-y and there is an
else
clause, evaluate and return<else-expression>
.
As you can see, cond
is a special form because it does not evaluate its operands in their entirety; the predicates are evaluated separately from their corresponding return expression. In addition, the expression short circuits upon reaching the first predicate that evaluates to a truth-y value, leaving the remaining predicates unevaluated.
The following code is roughly equivalent (see the explanation in the if expression section):
Scheme | Python |
---|---|
|
|