Conditionals

The standard boolean objects for true and false are written as #t and #f. What really matters, though, are the objects that the Scheme conditional expressions (if, cond, and, or, when, unless, do) treat as true or false. The phrase “a true value” (or sometimes just “true”) means any object treated as true by the conditional expressions, and the phrase “a false value” (or “false”) means any object treated as false by the conditional expressions. Of all the Scheme values, only #f counts as false in conditional expressions. All other Scheme values, including #t, count as true. A test-expression is an expression evaluated in this manner for whether it is true or false.

test-expression ::= expression
consequent ::= expression
alternate ::= expression

Syntax: if test-expression consequent alternate

Syntax: if test-expression consequent

An if expression is evaluated as follows: first, test-expression is evaluated. If it yields a true value, then consequent is evaluated and its values are returned. Otherwise alternate is evaluated and its values are returned. If test yields #f and no alternate is specified, then the result of the expression is unspecified.

(if (> 3 2) 'yes 'no)          ⇒ yes
(if (> 2 3) 'yes 'no)          ⇒ no
(if (> 3 2)
    (- 3 2)
    (+ 3 2))                   ⇒ 1
(if #f #f)                     ⇒ unspecified

The consequent and alternate expressions are in tail context if the if expression itself is.

cond-clause ::= (test-expression expression …)
  | (test => expression)

Syntax: cond cond-clause cond-clause

Syntax: cond cond-clause (else expression)

A cond expression is evaluated by evaluating the test-expressions of successive cond-clauses in order until one of them evaluates to a true value. When a test-expression evaluates to a true value, then the remaining expressions in its cond-clause are evaluated in order, and the results of the last expression in the cond-clause are returned as the results of the entire cond expression. If the selected cond-clause contains only the test-expression and no expressions, then the value of the test-expression is returned as the result. If the selected cond-clause uses the => alternate form, then the expression is evaluated. Its value must be a procedure. This procedure should accept one argument; it is called on the value of the test-expression and the values returned by this procedure are returned by the cond expression.

If all test-expressions evaluate to #f, and there is no else clause, then the conditional expression returns unspecified values; if there is an else clause, then its expressions are evaluated, and the values of the last one are returned.

(cond ((> 3 2) 'greater)
      ((< 3 2) 'less))         ⇒ greater

(cond ((> 3 3) 'greater)
      ((< 3 3) 'less)
      (else 'equal))           ⇒ equal

(cond ('(1 2 3) => cadr)
      (else #f))               ⇒ 2

For a cond-clause of one of the following forms:

(test expression …)
(else expression expression …)

the last expression is in tail context if the cond form itself is. For a cond clause of the form:

(test => expression)

the (implied) call to the procedure that results from the evaluation of expression is in a tail context if the cond form itself is.

Syntax: case key case-clause case-clause

key must be an expression.

case-clause ::= ((datum …) expression expression …)
  | (else expression expression …)

The second form, which specifies an “else clause”, may only appear as the last case-clause. Each datum is an external representation of some object. The data represented by the datums need not be distinct.

A case expression is evaluated as follows.

  1. key is evaluated and its result is compared using eqv? against the data represented by the datums of each case clause in turn, proceeding in order from left to right through the set of clauses.

  2. If the result of evaluating key is equivalent to a datum of a case clause, the corresponding expressions are evaluated from left to right and the results of the last expression in the case clause are returned as the results of the case expression. Otherwise, the comparison process continues.

  3. If the result of evaluating key is different from every datum in each set, then if there is an else clause its expressions are evaluated and the results of the last are the results of the case expression; otherwise the case expression returns unspecified values.

(case (* 2 3)
  ((2 3 5 7) 'prime)
  ((1 4 6 8 9) 'composite))    ⇒ composite
(case (car '(c d))
  ((a) 'a)
  ((b) 'b))                    ⇒ unspecified
(case (car '(c d))
  ((a e i o u) 'vowel)
  ((w y) 'semivowel)
  (else 'consonant))           ⇒ consonant

The last expression of a case clause is in tail context if the case expression itself is.

Syntax: and test-expression

If there are no test-expressions, #t is returned. Otherwise, the test-expression are evaluated from left to right until a test-expression returns #f or the last test-expression is reached. In the former case, the and expression returns #f without evaluating the remaining expressions. In the latter case, the last expression is evaluated and its values are returned.

(and (= 2 2) (> 2 1))          ⇒  #t
(and (= 2 2) (< 2 1))          ⇒  #f
(and 1 2 'c '(f g))            ⇒  (f g)
(and)                          ⇒  #t

The and keyword could be defined in terms of if using syntax-rules as follows:

(define-syntax and
  (syntax-rules ()
    ((and) #t)
    ((and test) test)
    ((and test1 test2 ...)
     (if test1 (and test2 ...) #t))))

The last test-expression is in tail context if the and expression itself is.

Syntax: or test-expression

If there are no test-expressions, #f is returned. Otherwise, the test-expressions are evaluated from left to right until a test-expression returns a true value val or the last test-expression is reached. In the former case, the or expression returns val without evaluating the remaining expressions. In the latter case, the last expression is evaluated and its values are returned.

(or (= 2 2) (> 2 1))           ⇒ #t
(or (= 2 2) (< 2 1))           ⇒ #t
(or #f #f #f)                  ⇒ #f
(or '(b c) (/ 3 0))            ⇒ (b c)

The or keyword could be defined in terms of if using syntax-rules as follows:

(define-syntax or
  (syntax-rules ()
    ((or) #f)
    ((or test) test)
    ((or test1 test2 ...)
     (let ((x test1))
       (if x x (or test2 ...))))))

The last test-expression is in tail context if the or expression itself is.

Syntax: when test-expression form...

If test-expression is true, evaluate each form in order, returning the value of the last one.

Syntax: unless test-expression form...

If test-expression is false, evaluate each form in order, returning the value of the last one.