# LispKit Dynamic

## Dynamic bindings

(make-parameter init) [procedure]
(make-parameter init converter)

Returns a newly allocated parameter object, which is a procedure that accepts zero arguments and returns the value associated with the parameter object. Initially, this value is the value of `(`converter init`)`, or of init if the conversion procedure converter is not specified. The associated value can be temporarily changed using `parameterize`. The default associated value can be changed by invoking the parameter object as a function with the new value as the only argument.

Parameter objects can be used to specify configurable settings for a computation without the need to pass the value to every procedure in the call chain explicitly.

(parameterize ((param value) …) body) [syntax]

A `parameterize` expression is used to change the values returned by specified parameter objects param during the evaluation of body. The param and value expressions are evaluated in an unspecified order. The body is evaluated in a dynamic environment in which calls to the parameters return the results of passing the corresponding values to the conversion procedure specified when the parameters were created. Then the previous values of the parameters are restored without passing them to the conversion procedure. The results of the last expression in the body are returned as the results of the entire `parameterize` expression.

    (define radix
      (make-parameter 10 (lambda (x)
                           (if (and (exact-integer? x) (<= 2 x 16))
                               x
                               (error "invalid radix")))))
    (define (f n) (number->string n (radix)))
    (f 12)                              ⇒  "12"
    (parameterize ((radix 2)) (f 12))   ⇒  "1100"
    (f 12)                              ⇒  "12"
    (radix 16)
    (parameterize ((radix 0)) (f 12))   ⇒  error: invalid radix

(make-dynamic-environment) [syntax]

Returns a newly allocated copy of the current dynamic environment. Dynamic environments are represented as mutable hashtables.

(dynamic-environment) [syntax]

Returns the current dynamic environment represented as mutable hashtables.

(set-dynamic-environment! hashtable) [syntax]

Sets the current dynamic environment to the given dynamic environment object. Dynamic environments are modeled as hashtables.

## Continuations

(continuation? obj) [procedure]

Returns `#t` if obj is a continuation procedure, `#f` otherwise.

(call-with-current-continuation proc) [procedure]
(call/cc proc)

The procedure `call-with-current-continuation` (or its equivalent abbreviation `call/cc`) packages the current continuation as an “escape procedure” and passes it as an argument to proc. It is an error if proc does not accept one argument.

The escape procedure is a Scheme procedure that, if it is later called, will abandon whatever continuation is in effect at that later time and will instead use the continuation that was in effect when the escape procedure was created. Calling the escape procedure will cause the invocation of before and after thunks installed using `dynamic-wind`.

The escape procedure accepts the same number of arguments as the continuation to the original call to `call-with-current-continuation`. Most continuations take only one value. Continuations created by the `call-with-values` procedure (including the initialization expressions of `define-values`, `let-values`, and `let*-values` expressions), take the number of values that the consumer expects. The continuations of all non-final expressions within a sequence of expressions, such as in `lambda`, `case-lambda`, `begin`, `let`, `let*`, `letrec`, `letrec*`, `let-values`, `let*-values`, `let-syntax`, `letrec-syntax`, `parameterize`, `guard`, `case`, `cond`, `when`, and `unless` expressions, take an arbitrary number of values because they discard the values passed to them in any event. The effect of passing no val- ues or more than one value to continuations that were not created in one of these ways is unspecified.

The escape procedure that is passed to proc has unlimited extent just like any other procedure in Scheme. It can be stored in variables or data structures and can be called as many times as desired. However, like the `raise` and `error` procedures, it never returns to its caller.

The following examples show only the simplest ways in which `call-with-current-continuation` is used. If all real uses were as simple as these examples, there would be no need for a procedure with the power of `call-with-current-continuation`.

    (call-with-current-continuation
      (lambda (exit)
        (for-each (lambda (x) (if (negative? x) (exit x)))
                  '(54 0 37 -3 245 19)) #t))  ⇒  -3
    (define list-length
      (lambda (obj)
        (call-with-current-continuation
          (lambda (return)
            (letrec
              ((r (lambda (obj)
                    (cond ((null? obj) 0)
                          ((pair? obj) (+ (r (cdr obj)) 1))
                          (else        (return #f))))))
              (r obj))))))
    (list-length '(1 2 3 4))     ⇒  4
    (list-length '(a b . c))     ⇒  #f

(dynamic-wind before thunk after) [procedure]

Calls thunk without arguments, returning the result(s) of this call. before and after are called, also without arguments, as required by the following rules. Note that, in the absence of calls to continuations captured using `call-with-current-continuation`, the three arguments are called once each, in order. before is called whenever execution enters the dynamic extent of the call to thunk and after is called whenever it exits that dynamic extent. The dynamic extent of a procedure call is the period between when the call is initiated and when it returns. The before and after thunks are called in the same dynamic environment as the call to `dynamic-wind`. In Scheme, because of `call-with-current-continuation`, the dynamic extent of a call is not always a single, connected time period. It is defined as follows:

- The dynamic extent is entered when execution of the body of the called procedure begins.
- The dynamic extent is also entered when execution is not within the dynamic extent and a continuation is invoked that was captured (using `call-with-current-continuation`) during the dynamic extent.
- It is exited when the called procedure returns.
- It is also exited when execution is within the dynamic extent and a continuation is invoked that was captured while not within the dynamic extent.

If a second call to `dynamic-wind` occurs within the dynamic extent of the call to thunk and then a continuation is invoked in such a way that the afters from these two invocations of `dynamic-wind` are both to be called, then the after associated with the second (inner) call to `dynamic-wind` is called first.

If a second call to `dynamic-wind` occurs within the dynamic extent of the call to thunk and then a continuation is invoked in such a way that the befores from these two invocations of `dynamic-wind` are both to be called, then the before associated with the first (outer) call to `dynamic-wind` is called first.

If invoking a continuation requires calling the before from one call to `dynamic-wind` and the after from another, then the after is called first.

The effect of using a captured continuation to enter or exit the dynamic extent of a call to before or after is unspecified.

    (let ((path ’())
          (c #f))
      (let ((add (lambda (s)
            (set! path (cons s path)))))
        (dynamic-wind
          (lambda () (add 'connect))
          (lambda () (add (call-with-current-continuation
                       (lambda (c0) (set! c c0) 'talk1))))
          (lambda () (add 'disconnect)))
        (if (< (length path) 4)
            (c 'talk2)
            (reverse path))))
      ⇒  (connect talk1 disconnect connect talk2 disconnect)

(unwind-protect body cleanup …) [syntax]

Executes expression body guaranteeing that statements cleanup … are executed when body’s execution is finished or when an exception is thrown during the execution of body. `unwind-protect` returns the result of executing body.

(return obj) [procedure]

Returns to the top-level of the read-eval-print loop with obj as the result (or terminates the program with obj as its return value).

## Exceptions

(current-exception-handler) [procedure]

Returns the current exception handler, which is a procedure that accepts one argument (the exception object). This is useful for inspecting or wrapping the current exception handling behavior.

(with-exception-handler handler thunk) [procedure]

The `with-exception-handler` procedure returns the results of invoking thunk. handler is installed as the current exception handler in the dynamic environment used for the invocation of thunk. It is an error if handler does not accept one argument. It is also an error if thunk does not accept zero arguments.

    (call-with-current-continuation
      (lambda (k)
        (with-exception-handler
          (lambda (x)
            (display "condition: ")(write x)(newline)(k 'exception))
          (lambda ()
            (+ 1 (raise 'an-error))))))  ⇒ exception; prints "condition: an-error"
    (with-exception-handler
      (lambda (x) (display "something went wrong\n"))
      (lambda () (+ 1 (raise 'an-error))))   ⇒ prints "something went wrong"

After printing, the second example then raises another exception: “exception handler returned”.

(try thunk) [procedure]
(try thunk handler)

`try` executes argument-less procedure thunk and returns the result as the result of `try` if thunk’s execution completes normally. If an exception is thrown, procedure handler is called with the exception object as its argument. The result of executing handler is returned by try.

(guard (var cond-clause …) body) [syntax]

The body is evaluated with an exception handler that binds the raised object to var and, within the scope of that binding, evaluates the clauses as if they were the clauses of a `cond` expression. That implicit `cond` expression is evaluated with the continuation and dynamic environment of the `guard` expression. If every cond-clause’s test evaluates to `#f` and there is no “else” clause, then `raise-continuable` is invoked on the raised object within the dynamic environment of the original call to `raise` or `raise-continuable`, except that the current exception handler is that of the `guard` expression.

Please note that each cond-clause is as in the specification of `cond`.

    (guard (condition
             ((assq ’a condition) => cdr)
             ((assq ’b condition)))
      (raise (list (cons ’a 42))))         ⇒  42
    (guard (condition
             ((assq ’a condition) => cdr)
             ((assq ’b condition)))
      (raise (list (cons ’b 23))))         ⇒ (b . 23)

(make-error message irrlist) [procedure]

Returns a newly allocated custom error object consisting of message as its error message and the list of irritants irrlist.

(make-assertion-error procname expr) [procedure]

Returns a newly allocated assertion error object referring to a procedure of name procname and an expression expr which triggered the assertion. Assertion errors that were raised should never be caught as they indicate a violation of an invariant.

(raise obj) [procedure]

Raises an exception by invoking the current exception handler on obj. The handler is called with the same dynamic environment as that of the call to `raise`, except that the current exception handler is the one that was in place when the handler being called was installed. If the handler returns, a secondary exception is raised in the same dynamic environment as the handler. The relationship between obj and the object raised by the secondary exception is unspecified.

(raise-continuable obj) [procedure]

Raises an exception by invoking the current exception handler on obj. The handler is called with the same dynamic environment as the call to `raise-continuable`, except that: (1) the current exception handler is the one that was in place when the handler being called was installed, and (2) if the handler being called returns, then it will again become the current exception handler. If the handler returns, the values it returns become the values returned by the call to `raise-continuable`.

    (with-exception-handler
      (lambda (con)
        (cond ((string? con) (display con))
              (else          (display "a warning has been issued")))
        42)
      (lambda ()
        (+ (raise-continuable "should be a number") 23)))
    prints: should be a number
      ⇒  65

(error message obj …) [procedure]

Raises an exception as if by calling `raise` on a newly allocated error object which encapsulates the information provided by message, as well as any obj, known as the irritants. The procedure `error-object?` must return `#t` on such objects. message is required to be a string.

    (define (null-list? l)
      (cond ((pair? l) #f)
            ((null? l) #t)
            (else (error "null-list?: argument out of domain" l))))

(assertion expr) [procedure]

Raises an exception as if by calling `raise` on a newly allocated assertion error object encapsulating expr as the expression which triggered the assertion failure and the current procedure’s name. Assertion errors that are raised via `assertion` should never be caught as they indicate a violation of a critical invariant.

    (define (null-list? l)
      (cond ((pair? l) #f)
            ((null? l) #t)
            (else (assertion '(list? l)))))

(assert expr0 expr1 …) [syntax]

Executes expr0, expr1, … in the given order and raises an assertion error as soon as the first expression is evaluating to `#f`. The raised assertion error encapsulates the expression that evaluated to `#f` and the name of the procedure in which the `assert` statement was placed.

    (define (drop-elements xs n)
      (assert (list? xs) (fixnum? n) (not (negative? n)))
      (if (or (null? xs) (zero? n)) xs (drop-elements (cdr xs) (fx1- n))))

(error-object? obj) [procedure]

Returns `#t` if obj is an error object, `#f` otherwise. Error objects are either implicitly created via `error` or they are created explicitly with procedure `make-error`.

(error-object-message err) [procedure]
(error-object-message err template?)

Returns the message (which is a string) encapsulated by the error object err with placeholders getting expanded. If template? is provided and set to `#t`, placeholders are not getting expanded, i.e. the message that is returned is the error message template string.

(error-object-irritants err) [procedure]

Returns a list of the irritants encapsulated by the error object err.

(error-object-stacktrace err) [procedure]

Returns a list of procedures representing the stack trace encapsulated by the error object err. The stack trace reflects the currently active procedures at the time the error object was created (either implicitly via `error` or explicitly via `make-error`).

(error-object->string err) [procedure]
(error-object->string err expanded?)

Returns a string representation of err for the purpose of displaying a description of the error. If expanded? is provided and set to `#t`, then a more comprehensive description is returned. If expanded? is set to symbol `printable`, an even more comprehensive description is returned.

(read-error? obj) [procedure]

This error type predicate returns `#t` if obj is an error object raised by the `read` procedure; otherwise, it returns `#f`.

(file-error? obj) [procedure]

This error type predicate returns `#t` if obj is an error object raised by the inability to open an input or output port on a file; otherwise, it returns `#f`.

## Exiting

(exit) [procedure]
(exit obj)

Runs all outstanding `dynamic-wind` after procedures, terminates the running program, and communicates an exit value to the operating system. If no argument is supplied, or if obj is `#t`, the `exit` procedure should communicate to the operating system that the program exited normally. If obj is `#f`, the `exit` procedure will communicate to the operating system that the program exited abnormally. Otherwise, `exit` should translate obj into an appropriate exit value for the operating system, if possible. The `exit` procedure must not signal an exception or return to its continuation.

(emergency-exit) [procedure]
(emergency-exit obj)

Terminates the program without running any outstanding `dynamic-wind` “after procedures” and communicates an exit value to the operating system in the same manner as `exit`.

(abort-eventually) [procedure]

Signals that execution should be aborted as soon as possible. This procedure is typically used in response to user cancellation requests or when a computation should be terminated gracefully. Unlike `exit` or `emergency-exit`, this procedure returns normally and allows the current computation to continue, but sets a flag that will cause the interpreter to abort when it checks for cancellation.