Most functions used for branching, such as < and string? , produce either #t or #f. Racket’s branching forms, however, treat any value other than #f as true. We say a true value to mean any value other than #f.
This convention for “true value” meshes well with protocols where #f can serve as failure or to indicate that an optional value is not supplied. (Beware of overusing this trick, and remember that an exception is usually a better mechanism to report failure.)
For example, the member function serves double duty; it can be used to find the tail of a list that starts with a particular item, or it can be used to simply check whether an item is present in a list:
#f
'("Groucho" "Zeppo")
'nope
'yep
+Conditionals: if, cond, and, and or in The Racket Reference also documents if .
In an if form,
the test-expr is always evaluated. If it produces any value other than #f, then then-expr is evaluated. Otherwise, else-expr is evaluated.
An if form must have both a then-expr and an else-expr; the latter is not optional. To perform (or skip) side-effects based on a test-expr, use when or unless , which we describe later in Sequencing.
+Conditionals: if, cond, and, and or in The Racket Reference also documents and and or .
Racket’s and and or are syntactic forms, rather than functions. Unlike a function, the and and or forms can skip evaluation of later expressions if an earlier one determines the answer.
An and form produces #f if any of its exprs produces #f. Otherwise, it produces the value of its last expr. As a special case, (and ) produces #t.
The or form produces #f if all of its exprs produce #f. Otherwise, it produces the first non-#f value from its exprs. As a special case, (or ) produces #f.
> (got-milk?'(applebanana))#f
> (got-milk?'(applemilkbanana))#t
If evaluation reaches the last expr of an and or or form, then the expr’s value directly determines the and or or result. Therefore, the last expr is in tail position, which means that the above got-milk? function runs in constant space.
+Tail Recursion introduces tail calls and tail positions.
The cond form chains a series of tests to select a result expression. To a first approximation, the syntax of cond is as follows:
+Conditionals: if, cond, and, and or in The Racket Reference also documents cond .
...)
Each test-expr is evaluated in order. If it produces #f, the corresponding bodys are ignored, and evaluation proceeds to the next test-expr. As soon as a test-expr produces a true value, the associated bodys are evaluated to produce the result for the cond form, and no further test-exprs are evaluated.
The last test-expr in a cond can be replaced by else . In terms of evaluation, else serves as a synonym for #t, but it clarifies that the last clause is meant to catch all remaining cases. If else is not used, then it is possible that no test-exprs produce a true value; in that case, the result of the cond expression is #<void>.
'ok
'ok
> (got-milk?'(applebanana))#f
> (got-milk?'(applemilkbanana))#t
The full syntax of cond includes two more kinds of clauses:
The => variant captures the true result of its test-expr and passes it to the result of the proc-expr, which must be a function of one argument.
> (after-groucho'("Harpo""Groucho""Zeppo"))'("Zeppo")
> (after-groucho'("Harpo""Zeppo"))not there
A clause that includes only a test-expr is rarely used. It captures the true result of the test-expr, and simply returns the result for the whole cond expression.