Writing Conditions

Choose if, cond, or case for your question, and see which expressions run.

Choose a conditional

Use if for one yes/no question, cond for several conditions, and case to compare one value with fixed data. This page shows which expressions each form evaluates. Forms such as cond and case that run by expanding into other forms are called derived forms.

See it run

LISPEX
(case 2 ((1) 'one) ((2) 'two) (else 'other))

Observed result

OUTPUT
two

case evaluates 2 once and selects the second clause. It returns the symbol two without evaluating the bodies of the other clauses.

LISPEX
(if #t 42 (/ 1 0))
(cond ((< 3 0) (/ 1 0))
      ((< 3 5) 'small)
      (else 'large))

Observed result

42
small

if evaluates its test, then only the selected branch. cond tests conditions in order and runs the body of the first true clause. It skips later clauses, including their tests. Neither division runs in this example.

Run each block in the playground. The lines above show the resulting values.

Read the forms

A form is a piece of program syntax, such as (if #t 1 0). A datum is one item of data, such as a number, symbol, or list. In case, the data in each clause are compared with the key using eqv?. They are not evaluated as expressions.

Only #f is false. Every other value counts as true.

FormUse it whenResult behavior
ifone test chooses between two branchesreturns the values from the selected branch
condseveral conditions describe different casesreturns the values from the first matching clause
caseone value is compared with fixed dataevaluates the key once and runs the matching clause
and / orlater tests depend on earlier resultsstops at the first false / true value and returns an operand value
when / unlessa body should run in only one casereturns zero values when the body is skipped

and and or stop as soon as the result is known. This is called short-circuit evaluation. They return an operand value without converting it to a boolean.

Run a body conditionally

when runs its body in order when the test is true. unless runs its body when the test is false. Each returns the result of the last body expression.

(when #t 42) returns 42, and (unless #f 7) returns 7. When the body is skipped, the form returns zero values. That happens with when on #f and with unless on a true value.

To handle a catchable error, use (guard (variable clause ...) body ...). guard binds the caught object to variable and tries the clauses in order, as cond does. A final else clause handles any remaining case. If no clause matches, guard raises the original error again.

Check the syntax before running

  • if requires a test and both branches. (if #t 1) raises E130 because the false branch is missing.
  • If no clause matches in cond or case and there is no else, the result is zero values. Using that result where one value is required raises E320.
  • else has a special meaning at the head of a cond, case, or guard clause. It is not reserved, so (define else 5) is accepted.
  • cond rejects an arrow clause using => with E130. In a case clause body, => is an ordinary name. Evaluating that name without a binding raises E300.
  • unquote and unquote-splicing outside quasiquote cause static errors, detected before execution.

Skipping a branch skips its evaluation. Lispex still checks the syntax of the whole program before running it.

How shorthand runs

Lispex rewrites shorthand into core forms before execution. This step is called normalization. The rules for cond, case, and, or, when, unless, let*, named let, do, and quasiquote are built in.

Normalization preserves evaluation order and tail positions. An expression is in tail position when its result is returned directly, with no further work in that call. Generated names cannot collide with your names, and your bindings cannot replace the hidden built-in operations.

Lispex uses these built-in rules for expansion. It rejects define-syntax and user-defined macros.

Keep going

Practice choosing conditions in Data and decisions. See how the shorthand is rewritten in Syntax That Expands into Basic Forms.