Guile provides three syntactic constructs for conditional evaluation.
if
is the normal if-then-else expression (with an optional else
branch), cond
is a conditional expression with multiple branches,
and case
branches if an expression has one of a set of constant
values.
All arguments may be arbitrary expressions. First, test is
evaluated. If it returns a true value, the expression consequent
is evaluated and alternate is ignored. If test evaluates to
#f
, alternate is evaluated instead. The values of the
evaluated branch (consequent or alternate) are returned as
the values of the if
expression.
When alternate is omitted and the test evaluates to
#f
, the value of the expression is not specified.
When you go to write an if
without an alternate (a one-armed
if
), part of what you are expressing is that you don’t care
about the return value (or values) of the expression. As such, you are
more interested in the effect of evaluating the consequent
expression. (By convention, we use the word statement to refer to
an expression that is evaluated for effect, not for value).
In such a case, it is considered more clear to express these intentions
with the special forms when
and unless
. As an added
bonus, these forms take a body like in a let
expression,
which can contain internal definitions and multiple statements to
evaluate (see Local Variable Bindings).
The actual definitions of these forms may be their most clear documentation:
(define-syntax-rule (when test stmt stmt* ...) (if test (let () stmt stmt* ...))) (define-syntax-rule (unless test stmt stmt* ...) (if (not test) (let () stmt stmt* ...)))
That is to say, when
evaluates its consequent statements in order
if test is true. unless
is the opposite: it evaluates the
statements if test is false.
Each cond
-clause must look like this:
(test body)
where test is an arbitrary expression, or like this
(test => expression)
where expression must evaluate to a procedure.
The tests of the clauses are evaluated in order and as soon as one
of them evaluates to a true value, the corresponding body is
evaluated to produce the result of the cond
-expression. For the
=>
clause type,
expression is evaluated and the resulting procedure is applied to
the value of test. The result of this procedure application is
then the result of the cond
-expression.
One additional cond
-clause is available as an extension to
standard Scheme:
(test guard => expression)
where guard and expression must evaluate to procedures.
For this clause type, test may return multiple values, and
cond
ignores its boolean state; instead, cond
evaluates
guard and applies the resulting procedure to the value(s) of
test, as if guard were the consumer argument of
call-with-values
. If the result of that procedure call is a
true value, it evaluates expression and applies the resulting
procedure to the value(s) of test, in the same manner as the
guard was called.
The test of the last clause may be the symbol else
.
Then, if none of the preceding tests is true, the
body following the else
is evaluated to produce the
result of the cond
-expression.
key may be any expression, and the clauses must have the form
((datum1 ...) body)
or
((datum1 ...) => expression)
and the last clause may have the form
(else body)
or
(else => expression)
All datums must be distinct. First, key is evaluated. The
result of this evaluation is compared against all datum values
using eqv?
. When this comparison succeeds, the body
following the datum is evaluated to produce the result of the
case
expression.
If the key matches no datum and there is an
else
-clause, the body following the else
is
evaluated to produce the result of the case
expression. If there
is no such clause, the result of the expression is unspecified.
For the =>
clause types, expression is evaluated and the
resulting procedure is applied to the value of key. The result of
this procedure application is then the result of the
case
-expression.