Skip to content

Control Flow

Procedures for managing program flow including continuations, multiple values, exceptions, and dynamic binding. Available from (scheme base).


Procedure Application

apply

Syntax: (apply proc arg1 ... args)

Calls proc with the given arguments. The last argument must be a list; its elements are spread as individual arguments. Any arguments before the final list are prepended as individual arguments.

kaappi> (apply + '(1 2 3))
;=> 6
kaappi> (apply + 1 2 '(3 4))
;=> 10
kaappi> (apply list 'a 'b '(c d))
;=> (a b c d)
kaappi> (apply string #\h #\i '())
;=> "hi"

Note

apply requires at least two arguments: the procedure and the trailing list. The trailing list is always spread, so (apply + '(1 2 3)) is equivalent to (+ 1 2 3).

See also: map, for-each, call-with-values


Continuations

call-with-current-continuation

Syntax: (call-with-current-continuation proc)

Captures the current continuation and passes it as an escape procedure to proc. The escape procedure, when called with a value, abandons the current computation and returns that value to the point where call-with-current-continuation was called. The continuation can be invoked multiple times and from outside the dynamic extent of the original call.

kaappi> (call-with-current-continuation
         (lambda (k) (k 42)))
;=> 42
kaappi> (call-with-current-continuation
         (lambda (k) (+ 1 (k 42))))
;=> 42
kaappi> (let ((saved #f))
         (let ((result (call-with-current-continuation
                         (lambda (k) (set! saved k) 0))))
           (if (< result 3)
               (saved (+ result 1))
               result)))
;=> 3

See also: call/cc, call/ec, dynamic-wind


call/cc

Syntax: (call/cc proc)

An alias for call-with-current-continuation. The captured continuation can be called any number of times and from any dynamic context. This is the most powerful form of continuation but also the most expensive, as the runtime must preserve the full call stack.

kaappi> (call/cc (lambda (k) (k 42)))
;=> 42
kaappi> (+ 1 (call/cc (lambda (k) (+ 2 (k 3)))))
;=> 4

See also: call-with-current-continuation, call/ec


call-with-escape-continuation

Syntax: (call-with-escape-continuation proc)

Like call-with-current-continuation, but the continuation can only be called during the dynamic extent of proc. After proc returns normally, invoking the escape continuation raises an error. Because the runtime knows the continuation will not be used after proc returns, it can be implemented more efficiently than a full continuation.

kaappi> (call-with-escape-continuation
         (lambda (exit) (exit 42)))
;=> 42
kaappi> (call-with-escape-continuation
         (lambda (exit)
           (for-each (lambda (x)
                       (when (negative? x) (exit x)))
                     '(3 1 -4 1 5))
           'all-positive))
;=> -4

See also: call/ec, call-with-current-continuation


call/ec

Syntax: (call/ec proc)

An alias for call-with-escape-continuation. The escape continuation is a one-shot exit: it can only be called within the dynamic extent of proc. More efficient than call/cc because the runtime does not need to preserve the continuation after proc returns.

kaappi> (call/ec (lambda (exit) (exit 'done)))
;=> done
kaappi> (call/ec
         (lambda (return)
           (let loop ((i 0))
             (when (= i 5) (return i))
             (loop (+ i 1)))))
;=> 5

See also: call-with-escape-continuation, call/cc


dynamic-wind

Syntax: (dynamic-wind before thunk after)

Calls thunk, guaranteeing that before is called when control enters the dynamic extent of thunk and after is called when control leaves. If a continuation captured inside thunk is invoked from outside, before is called again upon re-entry; if a continuation captured outside thunk is invoked from inside, after is called upon exit. All three arguments are zero-argument procedures (thunks).

kaappi> (let ((log '()))
         (dynamic-wind
           (lambda () (set! log (cons 'in log)))
           (lambda () (set! log (cons 'body log)))
           (lambda () (set! log (cons 'out log))))
         (reverse log))
;=> (in body out)
kaappi> (let ((log '())
              (k #f))
         (dynamic-wind
           (lambda () (set! log (cons 'in log)))
           (lambda () (call/cc (lambda (c) (set! k c)))
                      (set! log (cons 'body log)))
           (lambda () (set! log (cons 'out log))))
         (when (< (length log) 6) (k #f))
         (reverse log))
;=> (in body out in body out)

See also: call/cc, with-exception-handler


Multiple Values

values

Syntax: (values obj ...)

Returns zero or more values. Multiple values are not first-class objects -- they must be received by a continuation that expects them, typically call-with-values or special forms like let-values and receive. A single value passed to values is equivalent to returning that value directly.

kaappi> (values 1 2 3)
;=> 1
;=> 2
;=> 3
kaappi> (values)
kaappi> (call-with-values (lambda () (values 1 2)) +)
;=> 3

See also: call-with-values


call-with-values

Syntax: (call-with-values producer consumer)

Calls producer with no arguments. The values returned by producer (which may use values to return multiple values) are passed as arguments to consumer. Returns whatever consumer returns.

kaappi> (call-with-values (lambda () (values 1 2 3)) list)
;=> (1 2 3)
kaappi> (call-with-values (lambda () (values 4 5)) +)
;=> 9
kaappi> (call-with-values (lambda () 42) (lambda (x) (* x x)))
;=> 1764

See also: values, apply


Dynamic Binding

with-exception-handler

Syntax: (with-exception-handler handler thunk)

Installs handler as the current exception handler for the dynamic extent of the call to thunk. If an exception is raised (by raise or raise-continuable) during the execution of thunk, handler is called with the raised object as its argument. The handler is called with the exception handler that was in effect before with-exception-handler was called.

If handler returns (only possible when the exception was raised by raise-continuable), the value returned by handler becomes the return value of the raise-continuable call. If the exception was raised by raise, returning from handler raises a new exception.

kaappi> (with-exception-handler
         (lambda (e) (display "caught: ") (display e) (newline) 42)
         (lambda () (raise-continuable "oops")))
caught: oops
;=> 42
kaappi> (call/cc
         (lambda (exit)
           (with-exception-handler
             (lambda (e) (exit (list 'caught e)))
             (lambda () (raise "boom")))))
;=> (caught "boom")

See also: raise, raise-continuable, error, dynamic-wind


Exceptions

raise

Syntax: (raise obj)

Raises an exception by invoking the current exception handler with obj as its argument. The exception handler is called in the dynamic environment of the raise call, with the exception handler that was in effect before the current one installed. If the handler returns, a new exception is raised (it is an error for a raise handler to return).

kaappi> (call/cc
         (lambda (exit)
           (with-exception-handler
             (lambda (e) (exit (string-append "error: " e)))
             (lambda () (raise "something went wrong")))))
;=> "error: something went wrong"

See also: raise-continuable, with-exception-handler, error


raise-continuable

Syntax: (raise-continuable obj)

Like raise, but allows the exception handler to return a value. The returned value becomes the result of the raise-continuable expression. This is used for conditions where the handler can supply a replacement value and execution continues normally.

kaappi> (with-exception-handler
         (lambda (e) (* e 10))
         (lambda () (+ 1 (raise-continuable 5))))
;=> 51

See also: raise, with-exception-handler


error

Syntax: (error message obj ...)

Creates a new error object with the string message and zero or more irritant objects, then raises it. This is the standard way to signal an error in Scheme programs. The message should describe what went wrong, and the irritants provide additional context (typically the offending values).

kaappi> (guard (e (#t (error-object-message e)))
         (error "index out of range" 5 '(0 3)))
;=> "index out of range"
kaappi> (guard (e (#t (error-object-irritants e)))
         (error "bad value" 42 'expected-string))
;=> (42 expected-string)

See also: error-object?, error-object-message, error-object-irritants, raise


error-object?

Syntax: (error-object? obj)

Returns #t if obj is an error object created by error or raised by the implementation, and #f otherwise. Error objects carry a message string and a (possibly empty) list of irritants.

kaappi> (guard (e (#t (error-object? e)))
         (error "boom" 'details))
;=> #t
kaappi> (error-object? "not an error")
;=> #f
kaappi> (error-object? 42)
;=> #f

See also: error, error-object-message, error-object-irritants, port?


error-object-message

Syntax: (error-object-message error-object)

Returns the message string from error-object. It is an error if the argument is not an error object.

kaappi> (guard (e (#t (error-object-message e)))
         (error "file not found" "/tmp/missing.txt"))
;=> "file not found"

See also: error, error-object?, error-object-irritants


error-object-irritants

Syntax: (error-object-irritants error-object)

Returns the list of irritants from error-object. The irritants are the extra arguments that were passed to error after the message string. If error was called with only a message, this returns the empty list. It is an error if the argument is not an error object.

kaappi> (guard (e (#t (error-object-irritants e)))
         (error "bad args" 1 2 3))
;=> (1 2 3)
kaappi> (guard (e (#t (error-object-irritants e)))
         (error "no extras"))
;=> ()

See also: error, error-object?, error-object-message


file-error?

Syntax: (file-error? obj)

Returns #t if obj is an error object raised by file I/O operations (such as open-input-file when the file does not exist), and #f otherwise. This allows programs to distinguish file-related errors from other kinds of errors in exception handlers.

kaappi> (guard (e (#t (file-error? e)))
         (open-input-file "/nonexistent/file"))
;=> #t
kaappi> (guard (e (#t (file-error? e)))
         (error "not a file error"))
;=> #f

See also: read-error?, error-object?, open-input-file


read-error?

Syntax: (read-error? obj)

Returns #t if obj is an error object raised by read or other parsing operations when the input is malformed, and #f otherwise. This allows programs to distinguish syntax errors from other kinds of errors in exception handlers.

kaappi> (guard (e (#t (read-error? e)))
         (read (open-input-string "(unclosed")))
;=> #t
kaappi> (guard (e (#t (read-error? e)))
         (error "not a read error"))
;=> #f

See also: file-error?, error-object?, read