• Aucun résultat trouvé

Some Other Control-Flow Constructs: cond, and, and or

We've already seen that the special form if is a kind of expression, which returns a value as well as affecting control flow. Scheme also has cond, a more general conditional construct, and the extended logical operators and and or. These are all value-returning expressions; they're also special forms, not procedures: they control whether expressions get evaluated, depending on the values returned by other expressions.

cond: cond is like if...elseif...else if... else...

and and or: and and or are "short-circuiting"

Go to the first, previous, next, last section, table of contents.

http://www.federated.com/~jim/schintro-v14/schintro_20.html11/3/2006 8:54:13 PM

An Introduction to Scheme and its Implementation - cond

Go to the first, previous, next, last section, table of contents.

cond

In most procedural programming languages, you can write a sequence of if tests using an extended version of if, something like this:

if test1 then

Scheme has a similar construct, a special form called cond. The above example might be written in Scheme as

Notice that each test-and-action pair is enclosed in parentheses. In this example, test1 is just a variable reference, not a procedure call, i.e., we're testing to see if the value of the variable test1 is

#f; if not, we'll execute (action1), i.e., call the procedure action1. If it is false, control "falls through" to the next test, and keeps going until one of the tests evaluates to a true value (anything but

#f).

Notice that we indent the actions corresponding to a test by one character. This lines the actions up directly under the tests, rather than under the opening parenthesis that groups them together.

The else clause of a cond is optional; if present, that branch will be taken "by default"---if none of the other conditions evaluates to a true value, the else branch will be taken.

We don't really need the else clause, because we could get the same effect by using a test expression that

http://www.federated.com/~jim/schintro-v14/schintro_21.html (1 of 4)11/3/2006 8:54:18 PM

An Introduction to Scheme and its Implementation - cond

always evaluates to a true value. One way of doing this is to use the literal #t, the true boolean, because it's always true. The code above is equivalent to a nested set of if expressions:

(if test1

Like an if, a cond returns the value of whatever "branch" it executes. If test1 is true, for example, the above cond will return the value returned from the procedure call (action1).

Remember that each branch of an if is a single expression; if you want to execute more than one

expression in a branch, you have to wrap the expressions in a begin. With cond, you don't have to do this. You can follow a test expression with more than one action expression, and Scheme will evaluate all of them, in order, and return the value of the last one, just like a begin or a procedure body.

Suppose we want to modify the above cond example so that it prints out the branch it's taking, as well as evaluating the action expression and returning its value. We can do this:

(cond (test1

An Introduction to Scheme and its Implementation - cond

(action3)) (else

(display "taking fourth (default) branch") (action4)))

This cond will return the same value as the original, because it always returns the value of the last expression in a branch. As it executes, however, it also displays what it's doing. We can use the cond both for value and for effect.

Be particularly careful about parentheses with cond. You must enclose each branch with a pair of parentheses around the test expression and the corresponding sequence of action expressions. If you want to call a procedure in any of those expressions, you must also put parentheses around the procedure call. In the above example, if we wanted the first test to be a call to a procedure test1---rather than just fetching the value of the variable test1---we'd write

(cond ((test1)

(Note the indenting here. We usually line up a test and the corresponding sequence of actions vertically, whether or not the expression starts with a parentheses. That is, we indent one space past the opening parenthesis of the pair of parentheses that goes around them all.)

The "extra" parentheses are necessary so that cond can tell which action sequences are grouped with which tests.

Don't be afraid to use cond for conditionals with only one or two branches. cond is often more convenient than if because it can execute a sequence of expressions, instead of just one. It's not uncommon to see things like this:

...

(cond ((foo) (bar) (baz)))

http://www.federated.com/~jim/schintro-v14/schintro_21.html (3 of 4)11/3/2006 8:54:18 PM

An Introduction to Scheme and its Implementation - cond

...

Don't be confused by this--there's only one branch to this cond, like a one-branch if. We could have written it

...

(if (foo)

(begin (bar) (baz))) ...

It's just more convenient to use cond so that we can call bar before calling baz and returning its result, without explicitly writing a begin expression to sequence them.

We say that cond is syntactic sugar for nested ifs with begins around the branches. There's nothing we can do with cond that we can't do straightforwardly with if and begin---cond just gives us a

"sweetened" syntax, i.e., one that's more convenient.

Most of the special forms in Scheme are like this--they're just a convenient way of writing things that you could write using more basic special forms. (There are only five "core" special forms that are really necessary, and the others are equivalent to combinations of those special forms.)

Go to the first, previous, next, last section, table of contents.

http://www.federated.com/~jim/schintro-v14/schintro_21.html (4 of 4)11/3/2006 8:54:18 PM

An Introduction to Scheme and its Implementation - and and or

Go to the first, previous, next, last section, table of contents.

and and or

The special forms and and or can be used as logical operators, but they can also be used as control structures, which is why they are special forms.

and takes any number of expressions, and evaluates them in sequence, until one of them returns #f or all of them have been evaluated. At the point where one returns #f, and returns that value as the value of the and expression. If none of them returns #f, it returns the value of the last subexpression.

This is really a control construct, not just a logical operator, because whether subexpressions get evaluated depends on the reults of the previous subexpressions.

and is often used to express both control flow and value returning, like a sequence of if tests. You can write something like

(and (try-first-thing) (try-second-thing) (try-third-thing))

If the three calls all return true values, and returns the value of the last one. If any of them returns #f, however, none of the rest are evaluated, and #f is returned as the value of the overall expression.

Likewise, or takes any number of arguments, and returns the value of the first one that returns a true value (i.e., anything but #f). It stops when it gets a true value, and returns it without evaluating the remaining subexpressions.

(or (try-first-thing) (try-second-thing) (try-third-thing))

or keeps trying subexpressions until one of them does return a true value; if that happens, or stops and returns that value. If none of them returns anything but #f, it returns #f.

not is just a procedure

not is a procedure that takes one argument, which may be any kind of Scheme value, and returns #t or

#f. If the argument value is #f (the unique false object), it returns #t, and otherwise returns #f. That is, all values count as true except for the false object--just as in a conditional. For example, (not 0)

http://www.federated.com/~jim/schintro-v14/schintro_22.html (1 of 2)11/3/2006 8:54:21 PM

An Introduction to Scheme and its Implementation - and and or

returns #f.

Given that and and or are special forms, you might think that the logical not operator is a special form as well. It isn't. It's just a procedure--in particular, a predicate.

This makes sense because not always evaluates its (one) argument, and returns a value. It doesn't treat any arguments specially--it's just a normal first-class procedure, whose argument is evaluated in the usual way before the procedure is actually called.

In general, operations that can be procedures are procedures. Scheme only has special forms for things that are actually special, and need their arguments treated differently from arguments to procedure calls.

(Even Scheme's most powerful control construct, call-with-current-continuation, is just a first-class procedure.)

==================================================================

This is the end of Hunk A.

TIME TO TRY IT OUT

At this point, you should go read Hunk B of the next chapter and work through the examples using a running Scheme system.

Then return here and resume this chapter.

==================================================================

(Go to Hunk B, which starts at section An Interactive Programming Environment (Hunk B).)

Go to the first, previous, next, last section, table of contents.

http://www.federated.com/~jim/schintro-v14/schintro_22.html (2 of 2)11/3/2006 8:54:21 PM

An Introduction to Scheme and its Implementation - Comments

Go to the first, previous, next, last section, table of contents.

Comments (Hunk C)

==================================================================

Hunk C starts here:

==================================================================

[ Should I say this earlier, and use comments in examples earlier? ]

You can and should put comments in your Scheme programs. Start a comment with a semicolon.

Scheme will ignore any characters after that on a line. (This is like the // comments in C++.) For example, here's a variable definition with a comment after it:

(define foo 22) ; define foo with an initial value of 22

Of course, most comments should tell you things that aren't patently obvious from looking at the code.

Standard Scheme does not have block comments like C's /*...*/ comments.

It is common to use two or three semicolons to start a comment, rather than just one. This makes the beginning of the comment stand out more than a single semicolon. The extra semicolons are ignored, along with all other characters up to the end of the line.

A common style is to use two semicolons for most comments, and three for comments that take up a whole line, or which describe the contents of a file.

Go to the first, previous, next, last section, table of contents.

http://www.federated.com/~jim/schintro-v14/schintro_23.html11/3/2006 8:54:30 PM

An Introduction to Scheme and its Implementation - Parentheses and Indenting

Go to the first, previous, next, last section, table of contents.