#
Chapter 4
Conditionals

Like all languages, Scheme provides conditionals. The basic form is the `if`:

    (if test-expression
        then-branch
        else-branch)

If `test-expression` evaluates to true (ie, any value other than `#f`), the ``then'' branch is evaluated. If not, the ``else'' branch is evaluated. The ``else'' branch is optional.

    (define p 80)

    (if (> p 70)
        'safe
        'unsafe)
    =>  safe

    (if (< p 90)
        'low-pressure) ;no ``else'' branch
    =>  low-pressure

Scheme provides some other conditional forms for convenience. They can all be defined as macros (chap 8) that expand into `if`-expressions.

## 4.1 `when` and `unless`

`when` and `unless` are convenient conditionals to use when only one branch (the ``then'' or the ``else'' branch) of the basic conditional is needed.

    (when (< (pressure tube) 60)
       (open-valve tube)
       (attach floor-pump tube)
       (depress floor-pump 5)
       (detach floor-pump tube)
       (close-valve tube))

Assuming `pressure` of `tube` is less than `60`, this conditional will attach `floor-pump` to `tube` and `depress` it `5` times. (`attach` and `depress` are some suitable procedures.)

The same program using `if` would be:

    (if (< (pressure tube) 60)
        (begin
          (open-valve tube)
          (attach floor-pump tube)
          (depress floor-pump 5)
          (detach floor-pump tube)
          (close-valve tube)))

Note that `when`'s branch is an implicit `begin`, whereas `if` requires an explicit `begin` if either of its branches has more than one form.

The same behavior can be written using `unless` as follows:

    (unless (>= (pressure tube) 60)
       (open-valve tube)
       (attach floor-pump tube)
       (depress floor-pump 5)
       (detach floor-pump tube)
       (close-valve tube))

Not all Schemes provide `when` and `unless`. If your Scheme does not have them, you can define them as macros (see chap 8).

## 4.2 `cond`

The `cond` form is convenient for expressing nested `if`-expressions, where each ``else'' branch but the last introduces a new `if`. Thus, the form

    (if (char<? c #\c) -1
        (if (char=? c #\c) 0
            1))

can be rewritten using `cond` as:

    (cond ((char<? c #\c) -1)
          ((char=? c #\c) 0)
          (else 1))

The `cond` is thus a multi-branch conditional. Each clause has a test and an associated action. The first test that succeeds triggers its associated action. The final `else` clause is chosen if no other test succeeded.

The `cond` actions are implicit `begin`s.

## 4.3 `case`

A special case of the `cond` can be compressed into a `case` expression. This is when every test is a membership test.

    (case c
      ((#\a) 1)
      ((#\b) 2)
      ((#\c) 3)
      (else 4))
    =>  3

The clause whose head contains the value of `c` is chosen.

## 4.4 `and` and `or`

Scheme provides special forms for boolean conjunction (``and'') and disjunction (``or''). (We have already seen (sec 2.1.1) Scheme's boolean negation `not`, which is a procedure.)

The special form `and` returns a true value if all its subforms are true. The actual value returned is the value of the final subform. If any of the subforms are false, `and` returns `#f`.

    (and 1 2)  =>  2
    (and #f 1) =>  #f

The special form `or` returns the value of its first true subform. If all the subforms are false, `or` returns `#f`.

    (or 1 2)  =>  1
    (or #f 1) =>  1

Both `and` and `or` evaluate their subforms left-to-right. As soon as the result can be determined, `and` and `or` will ignore the remaining subforms.

    (and 1 #f expression-guaranteed-to-cause-error)
    =>  #f

    (or 1 #f expression-guaranteed-to-cause-error)
    =>  1