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


Controlling the Flow of Program Execution

Evaluating a Sequence of Expressions

begin is used for grouping several expression together so that they syntactically are treated as if they were one expression. This is particularly important when syntactic expressions are used which only allow one expression, but the programmer wants to use more than one expression in that place. As an example, consider the conditional expression below:

(if (> x 0)
    (begin (display "greater") (newline)))

If the two calls to display and newline were not embedded in a begin-statement, the call to newline would get misinterpreted as the else-branch of the if-expression.

syntax: begin expr1 expr2 ...
The expression(s) are evaluated in left-to-right order and the value of the last expression is returned as the value of the begin-expression. This expression type is used when the expressions before the last one are evaluated for their side effects.

Simple Conditional Evaluation

Guile provides three syntactic constructs for conditional evaluation. if is the normal if-then-else expression (with an optional else branch), cond is a conditional expression with multiple branches and case branches if an expression has one of a set of constant values.

syntax: if test consequent [alternate]
All arguments may be arbitrary expressions. First, test is evaluated. If it returns a true value, the expression consequent is evaluated and alternate is ignored. If test evaluates to #f, alternate is evaluated instead. The value of the evaluated branch (consequent or alternate) is returned as the value of the if expression.

When alternate is omitted and the test evaluates to #f, the value of the expression is not specified.

syntax: cond clause1 clause2 ...
Each cond-clause must look like this:
(test expression ...)

where test and expression are arbitrary expression, or like this

(test => expression

where expression must evaluate to a procedure.

The tests of the clauses are evaluated in order and as soon as one of them evaluates to a true values, the corresponding expressions are evaluated in order and the last value is returned as the value of the cond-expression. For the => clause type, expression is evaluated and the resulting procedure is applied to the value of test. The result of this procedure application is then the result of the cond-expression.

The test of the last clause may be the keyword else. Then, if none of the preceding tests is true, the expressions following the else are evaluated to produce the result of the cond-expression.

syntax: case key clause1 clause2 ...
key may be any expression, the clauses must have the form
((datum1 ...) expr1 expr2 ...)

and the last clause may have the form

(else expr1 expr2 ...)

All datums must be distinct. First, key is evaluated. The the result of this evaluation is compared against all datums using eqv?. When this comparison succeeds, the expression(s) following the datum are evaluated from left to right, returning the value of the last expression as the result of the case expression.

If the key matches no datum and there is an else-clause, the expressions following the else are evaluated. If there is no such clause, the result of the expression is unspecified.

Conditional Evaluation of a Sequence of Expressions

and and or evaluate all their arguments, similar to begin, but evaluation stops as soon as one of the expressions evaluates to false or true, respectively.

syntax: and expr ...
Evaluate the exprs from left to right and stop evaluation as soon as one expression evaluates to #f; the remaining expressions are not evaluated. The value of the last evaluated expression is returned. If no expression evaluates to #f, the value of the last expression is returned.

If used without expressions, #t is returned.

syntax: or expr ...
Evaluate the exprs from left to right and stop evaluation as soon as one expression evaluates to a true value (that is, a value different from #f); the remaining expressions are not evaluated. The value of the last evaluated expression is returned. If all expressions evaluate to #f, #f is returned.

If used without expressions, #f is returned.

Iteration mechanisms

Scheme has only few iteration mechanisms, mainly because iteration in Scheme programs is normally expressed using recursion. Nevertheless, R5RS defines a construct for programming loops, calling do. In addition, Guile has an explicit looping syntax called while.

syntax: do ((variable1 init1 step1) ...) (test expr ...) command ...
The init expressions are evaluated and the variables are bound to their values. Then looping starts with testing the test expression. If test evaluates to a true value, the expr following the test are evaluated and the value of the last expr is returned as the value of the do expression. If test evaluates to false, the commands are evaluated in order, the steps are evaluated and stored into the variables and the next iteration starts.

Any of the step expressions may be omitted, so that the corresponding variable is not changed during looping.

syntax: while cond body ...
Evaluate all expressions in body in order, as long as cond evaluates to a true value. The cond expression is tested before every iteration, so that the body is not evaluated at all if cond is #f right from the start.

Another very common way of expressing iteration in Scheme programs is the use of the so-called named let.

Named let is a variant of let which creates a procedure and calls it in one step. Because of the newly created procedure, named let is more powerful than do--it can be used for iteration, but also for arbitrary recursion.

syntax: let variable bindings body
For the definition of bindings see the documentation about let (see section Local Variable Bindings).

Named let works as follows:

The next example implements a loop which iterates (by recursion) 1000 times.

(let lp ((x 1000))
  (if (positive? x)
      (lp (- x 1))
      x))
=>
0

Continuations

The ability to explicitly capture continuations using call-with-current-continuation (also often called call/cc for short), and to invoke such continuations later any number of times, and from any other point in a program, provides maybe the most powerful control structure known. All other control structures, such as loops and coroutines, can be emulated using continuations.

The implementation of continuations in Guile is not as efficient as one might hope, because it is constrained by the fact that Guile is designed to cooperate with programs written in other languages, such as C, which do not know about continuations. So continuations should be used when there is no other simple way of achieving the desired behaviour, or where the advantages of the elegant continuation mechanism outweigh the need for optimum performance. If you find yourself using call/cc for escape procedures and your program is running too slow, you might want to use exceptions (see section Exceptions) instead.

Scheme Procedure: call-with-current-continuation proc
Capture the current continuation and call proc with the captured continuation as the single argument. This continuation can then be called with arbitrarily many arguments. Such a call will work like a goto to the invocation location of call-with-current-continuation, passing the arguments in a way that they are returned by the call to call-with-current-continuation. Since it is legal to store the captured continuation in a variable or to pass it to other procedures, it is possible that a procedure returns more than once, even if it is called only one time. This can be confusing at times.
(define kont #f)
(call-with-current-continuation
  (lambda (k)
     (set! kont k)
     1))
=>
1

(kont 2)
=>
2

Returning and Accepting Multiple Values

Scheme allows a procedure to return more than one value to its caller. This is quite different to other languages which only allow single-value returns. Returning multiple values is different from returning a list (or pair or vector) of values to the caller, because conceptually not one compound object is returned, but several distinct values.

The primitive procedures for handling multiple values are values and call-with-values. values is used for returning multiple values from a procedure. This is done by placing a call to values with zero or more arguments in tail position in a procedure body. call-with-values combines a procedure returning multiple values with a procedure which accepts these values as parameters.

Scheme Procedure: values . args
C Function: scm_values (args)
Delivers all of its arguments to its continuation. Except for continuations created by the call-with-values procedure, all continuations take exactly one value. The effect of passing no value or more than one value to continuations that were not created by call-with-values is unspecified.

Scheme Procedure: call-with-values producer consumer
Calls its producer argument with no values and a continuation that, when passed some values, calls the consumer procedure with those values as arguments. The continuation for the call to consumer is the continuation of the call to call-with-values.
(call-with-values (lambda () (values 4 5))
                  (lambda (a b) b))
                                             ==>  5

(call-with-values * -)                             ==>  -1

In addition to the fundamental procedures described above, Guile has a module which exports a syntax called receive, which is much more convenient. If you want to use it in your programs, you have to load the module (ice-9 receive) with the statement

(use-modules (ice-9 receive))

library syntax: receive formals expr body ...
Evaluate the expression expr, and bind the result values (zero or more) to the formal arguments in the formal argument list formals. formals must have the same syntax like the formal argument list used in lambda (see section Lambda: Basic Procedure Creation). After binding the variables, the expressions in body ... are evaluated in order.

Exceptions

A common requirement in applications is to want to jump non-locally from the depths of a computation back to, say, the application's main processing loop. Usually, the place that is the target of the jump is somewhere in the calling stack of procedures that called the procedure that wants to jump back. For example, typical logic for a key press driven application might look something like this:

main-loop:
  read the next key press and call dispatch-key

dispatch-key:
  lookup the key in a keymap and call an appropriate procedure,
  say find-file

find-file:
  interactively read the required file name, then call
  find-specified-file

find-specified-file:
  check whether file exists; if not, jump back to main-loop
  ...

The jump back to main-loop could be achieved by returning through the stack one procedure at a time, using the return value of each procedure to indicate the error condition, but Guile (like most modern programming languages) provides an additional mechanism called exception handling that can be used to implement such jumps much more conveniently.

Exception Terminology

There are several variations on the terminology for dealing with non-local jumps. It is useful to be aware of them, and to realize that they all refer to the same basic mechanism.

Where signal and signalling are used, special care is needed to avoid the risk of confusion with POSIX signals. (Especially considering that Guile handles POSIX signals by throwing a corresponding kind of exception: REFFIXME.)

This manual prefers to speak of throwing and catching exceptions, since this terminology matches the corresponding Guile primitives.

Catching Exceptions

catch is used to set up a target for a possible non-local jump. The arguments of a catch expression are a key, which restricts the set of exceptions to which this catch applies, a thunk that specifies the normal case code -- i.e. what should happen if no exceptions are thrown -- and a handler procedure that says what to do if an exception is thrown. Note that if the normal case thunk executes normally, which means without throwing any exceptions, the handler procedure is not executed at all.

When an exception is thrown using the throw primitive, the first argument of the throw is a symbol that indicates the type of the exception. For example, Guile throws an exception using the symbol numerical-overflow to indicate numerical overflow errors such as division by zero:

(/ 1 0)
=>
ABORT: (numerical-overflow)

The key argument in a catch expression corresponds to this symbol. key may be a specific symbol, such as numerical-overflow, in which case the catch applies specifically to exceptions of that type; or it may be #t, which means that the catch applies to all exceptions, irrespective of their type.

The second argument of a catch expression should be a thunk (i.e. a procedure that accepts no arguments) that specifies the normal case code. The catch is active for the execution of this thunk, including any code called directly or indirectly by the thunk's body. Evaluation of the catch expression activates the catch and then calls this thunk.

The third argument of a catch expression is a handler procedure. If an exception is thrown, this procedure is called with exactly the arguments specified by the throw. Therefore, the handler procedure must be designed to accept a number of arguments that corresponds to the number of arguments in all throw expressions that can be caught by this catch.

Scheme Procedure: catch key thunk handler
C Function: scm_catch (key, thunk, handler)
Invoke thunk in the dynamic context of handler for exceptions matching key. If thunk throws to the symbol key, then handler is invoked this way:
(handler key args ...)

key is a symbol or #t.

thunk takes no arguments. If thunk returns normally, that is the return value of catch.

Handler is invoked outside the scope of its own catch. If handler again throws to the same key, a new handler from further up the call chain is invoked.

If the key is #t, then a throw to any symbol will match this call to catch.

If the handler procedure needs to match a variety of throw expressions with varying numbers of arguments, you should write it like this:

(lambda (key . args)
  ...)

The key argument is guaranteed always to be present, because a throw without a key is not valid. The number and interpretation of the args varies from one type of exception to another, but should be specified by the documentation for each exception type.

Note that, once the handler procedure is invoked, the catch that led to the handler procedure being called is no longer active. Therefore, if the handler procedure itself throws an exception, that exception can only be caught by another active catch higher up the call stack, if there is one.

Throwing Exceptions

The throw primitive is used to throw an exception. One argument, the key, is mandatory, and must be a symbol; it indicates the type of exception that is being thrown. Following the key, throw accepts any number of additional arguments, whose meaning depends on the exception type. The documentation for each possible type of exception should specify the additional arguments that are expected for that kind of exception.

Scheme Procedure: throw key . args
C Function: scm_throw (key, args)
Invoke the catch form matching key, passing args to the handler.

key is a symbol. It will match catches of the same symbol or of #t.

If there is no handler at all, Guile prints an error and then exits.

When an exception is thrown, it will be caught by the innermost catch expression that applies to the type of the thrown exception; in other words, the innermost catch whose key is #t or is the same symbol as that used in the throw expression. Once Guile has identified the appropriate catch, it handles the exception by applying that catch expression's handler procedure to the arguments of the throw.

If there is no appropriate catch for a thrown exception, Guile prints an error to the current error port indicating an uncaught exception, and then exits. In practice, it is quite difficult to observe this behaviour, because Guile when used interactively installs a top level catch handler that will catch all exceptions and print an appropriate error message without exiting. For example, this is what happens if you try to throw an unhandled exception in the standard Guile REPL; note that Guile's command loop continues after the error message:

guile> (throw 'badex)
<unnamed port>:3:1: In procedure gsubr-apply ...
<unnamed port>:3:1: unhandled-exception: badex
ABORT: (misc-error)
guile> 

The default uncaught exception behaviour can be observed by evaluating a throw expression from the shell command line:

$ guile -c "(begin (throw 'badex) (display \"here\\n\"))"
guile: uncaught throw to badex: ()
$ 

That Guile exits immediately following the uncaught exception is shown by the absence of any output from the display expression, because Guile never gets to the point of evaluating that expression.

Catch Without Unwinding

A lazy catch is used in the same way as a normal catch, with key, thunk and handler arguments specifying the exception type, normal case code and handler procedure, but differs in one important respect: the handler procedure is executed without unwinding the call stack from the context of the throw expression that caused the handler to be invoked.

Scheme Procedure: lazy-catch key thunk handler
C Function: scm_lazy_catch (key, thunk, handler)
This behaves exactly like catch, except that it does not unwind the stack before invoking handler. The handler procedure is not allowed to return: it must throw to another catch, or otherwise exit non-locally.

Typically, handler should save any desired state associated with the stack at the point where the corresponding throw occurred, and then throw an exception itself -- usually the same exception as the one it caught. If handler is invoked and does not throw an exception, Guile itself throws an exception with key misc-error.

Not unwinding the stack means that throwing an exception that is caught by a lazy-catch is almost equivalent to calling the lazy-catch's handler inline instead of each throw, and then omitting the surrounding lazy-catch. In other words,

(lazy-catch 'key
  (lambda () ... (throw 'key args ...) ...)
  handler)

is almost equivalent to

((lambda () ... (handler 'key args ...) ...))

But why only almost? The difference is that with lazy-catch (as with normal catch), the dynamic context is unwound back to just outside the lazy-catch expression before invoking the handler. (For an introduction to what is meant by dynamic context, See section Dynamic Wind.)

Then, when the handler itself throws an exception, that exception must be caught by some kind of catch (including perhaps another lazy-catch) higher up the call stack.

The dynamic context also includes with-fluids blocks (REFFIXME), so the effect of unwinding the dynamic context can also be seen in fluid variable values. This is illustrated by the following code, in which the normal case thunk uses with-fluids to temporarily change the value of a fluid:

(define f (make-fluid))
(fluid-set! f "top level value")

(define (handler . args)
  (cons (fluid-ref f) args))

(lazy-catch 'foo
            (lambda ()
              (with-fluids ((f "local value"))
                (throw 'foo)))
            handler)
=>
("top level value" foo)

((lambda ()
   (with-fluids ((f "local value"))
     (handler 'foo))))
=>
("local value" foo)

In the lazy-catch version, the unwinding of dynamic context restores f to its value outside the with-fluids block before the handler is invoked, so the handler's (fluid-ref f) returns the external value.

lazy-catch is useful because it permits the implementation of debuggers and other reflective programming tools that need to access the state of the call stack at the exact point where an exception or an error is thrown. For an example of this, see REFFIXME:stack-catch.

How Guile Implements Exceptions

It is traditional in Scheme to implement exception systems using call-with-current-continuation. Continuations (see section Continuations) are such a powerful concept that any other control mechanism -- including catch and throw -- can be implemented in terms of them.

Guile does not implement catch and throw like this, though. Why not? Because Guile is specifically designed to be easy to integrate with applications written in C. In a mixed Scheme/C environment, the concept of continuation must logically include "what happens next" in the C parts of the application as well as the Scheme parts, and it turns out that the only reasonable way of implementing continuations like this is to save and restore the complete C stack.

So Guile's implementation of call-with-current-continuation is a stack copying one. This allows it to interact well with ordinary C code, but means that creating and calling a continuation is slowed down by the time that it takes to copy the C stack.

The more targeted mechanism provided by catch and throw does not need to save and restore the C stack because the throw always jumps to a location higher up the stack of the code that executes the throw. Therefore Guile implements the catch and throw primitives independently of call-with-current-continuation, in a way that takes advantage of this upwards only nature of exceptions.

Procedures for Signaling Errors

Guile provides a set of convenience procedures for signaling error conditions that are implemented on top of the exception primitives just described.

Scheme Procedure: error msg args ...
Raise an error with key misc-error and a message constructed by displaying msg and writing args.

Scheme Procedure: scm-error key subr message args data
C Function: scm_error_scm (key, subr, message, args, data)
Raise an error with key key. subr can be a string naming the procedure associated with the error, or #f. message is the error message string, possibly containing ~S and ~A escapes. When an error is reported, these are replaced by formatting the corresponding members of args: ~A (was %s in older versions of Guile) formats using display and ~S (was %S) formats using write. data is a list or #f depending on key: if key is system-error then it should be a list containing the Unix errno value; If key is signal then it should be a list containing the Unix signal number; otherwise it will usually be #f.

Scheme Procedure: strerror err
C Function: scm_strerror (err)
Return the Unix error message corresponding to err, which must be an integer value.

syntax: false-if-exception expr
Returns the result of evaluating its argument; however if an exception occurs then #f is returned instead.

Dynamic Wind

[FIXME: this is pasted in from Tom Lord's original guile.texi and should be reviewed]

Scheme Procedure: dynamic-wind in_guard thunk out_guard
C Function: scm_dynamic_wind (in_guard, thunk, out_guard)
All three arguments must be 0-argument procedures. in_guard is called, then thunk, then out_guard.

If, any time during the execution of thunk, the continuation of the dynamic_wind expression is escaped non-locally, out_guard is called. If the continuation of the dynamic-wind is re-entered, in_guard is called. Thus in_guard and out_guard may be called any number of times.

(define x 'normal-binding)
=> x
(define a-cont  (call-with-current-continuation
		  (lambda (escape)
		     (let ((old-x x))
		       (dynamic-wind
			  ;; in-guard:
			  ;;
			  (lambda () (set! x 'special-binding))

			  ;; thunk
			  ;;
		 	  (lambda () (display x) (newline)
				     (call-with-current-continuation escape)
				     (display x) (newline)
				     x)

			  ;; out-guard:
			  ;;
			  (lambda () (set! x old-x)))))))

;; Prints:
special-binding
;; Evaluates to:
=> a-cont
x
=> normal-binding
(a-cont #f)
;; Prints:
special-binding
;; Evaluates to:
=> a-cont  ;; the value of the (define a-cont...)
x
=> normal-binding
a-cont
=> special-binding

How to Handle Errors in C Code

Error handling is based on catch and throw. Errors are always thrown with a key and four arguments:

In addition to catch and throw, the following Scheme facilities are available:

Scheme Procedure: scm-error key subr message args rest
Throw an error, with arguments as described above.

Scheme Procedure: error msg arg ...
Throw an error using the key 'misc-error. The error message is created by displaying msg and writing the args.

The following are the error keys defined by libguile and the situations in which they are used:

C Support

SCM scm_error (SCM key, char *subr, char *message, SCM args, SCM rest)

Throws an error, after converting the char * arguments to Scheme strings. subr is the Scheme name of the procedure, NULL is converted to #f. Likewise a NULL message is converted to #f.

The following procedures invoke scm_error with various error keys and arguments. The first three call scm_error with the system-error key and automatically supply errno in the "rest" argument: scm_syserror generates messages using strerror, scm_sysmissing is used when facilities are not available. Care should be taken that the errno value is not reset (e.g. due to an interrupt).

Exception handlers can also be installed from C, using scm_internal_catch, scm_lazy_catch, or scm_stack_catch from libguile/throw.c. These have not yet been documented, however the source contains some useful comments.


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