if conditional is the most basic code switch in more or less any programming language. In Scheme it has the general form
(if test consequent alternative)
If the expression
test evaluates to “a true value” then the subexpression
consequent is evaluated, otherwise
alternative, and the whole
if expression evaluates to the value of the chosen subexpression. OK, let's clarify this with an example, but first of all we have to understand what “a true value” means.
Scheme knows the literals
#t for “true” and
#f for “false”, which are returned by many comparing expressions and particularly all predicates:
guile> (> 2 1) #t guile> (string=? "Yes" "No") #f guile> (number? 1) #t guile> (list? "I'm a list?") #f
However, in Guile Scheme every object except
#f is considered to have “a true value”. So the following expressions all have “a true value”:
"Foo" 'bar '(1 . 2) '()
That means that whenever the expression
test evaluates to anything except
consequent is evaluated, otherwise
So here is the first concrete example
guile> (if (> 2 1) "Greater" "Smaller") "Greater" guile> (if (> 1 2) "Greater" "Smaller") "Smaller"
In the first case the test is the expression
(> 2 1) which evaluates to
#t (2 is greater than 1), therefore the
consequent subexpression is evaluated. In this case it is the self-evaluating string
"Greater", but it could as well be a complex expression or a symbol referring to a variable. This string then becomes the value of the whole
if expression, and therefore this is printed as the result.
In the second case the test expression evaluates to
#f, therefore the whole expression evaluates to
The most important thing to understand here is that the subexpressions evaluate to a value and don't necessarily do anything, and that the same is true for the whole
if expression. This is what I meant with the different paradigm: in Scheme an
if expression should be phrased colloquially as “depending on the result of the test this evaluates to one or the other” instead of “depending on the test do this or that”. This is best demonstrated in a local binding (which is also a common use case for conditionals):
#(display (let* ((rand (random 100)) (state (if (even? rand) "even" "odd"))) (format "The random number ~a is ~a" rand state)))
We have a
let* expression at the core of this example. It establishes two bindings, first a random integer and then its “state”. The value bound to the
state name is the result of an
if expression, namely one of the strings
“odd”, depending on the result of the application of the
even? procedure. The body of the
let* expression is the invocation of the
format procedure which evaluates to a string. Therefore the value of the whole
let* expression is the value of the
format expression, which is then passed to the
display procedure, which prints for example
The random number 61 is odd to the console.
The example discussed above is the default case for
if expressions, but there are a number of special cases you should know about - because they can be both confusing and useful. The first topic to discuss is the value of the subexpressions.
Depending on the test one subexpression will be evaluated, and its value becomes the value of the
if expression. However, expressions do not necessarily evaluate to a value but can also be
guile> (if #t (display "true") (display "false"))
(display "true") will print something to the console but doesn't evaluate to anything, and consequently the whole expression also has an unspecified value.
No alternative expression¶
The alternative expression can be omitted in an
if expression, making it
(if test consequent). This will work, but when the test fails (i.e. the alternative expression is requested to be evaluated) the value of the
if expression will be unspecified. This may be acceptable or not, depending on the context. For example, if the subexpression is used to do something instead of returning a value there's no problem at all.