doc.txt

Tail

_Tail_
_tail_

This collection provides one file:

 _tail.ss_: special forms for preserving and destroying tail position

This library provides a syntax for capturing a continuation and
binding it to a variable that, when applied, evaluates its
subexpression in tail position with respect to its parent
expression. It also contains a utility for evaluating an expression in
a guaranteed non-tail context.

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

> (let-tail-continuation k body1 body2 ...)
> (let/tc k body1 body2 ...)

A syntax for capturing a continuation a binding it to the syntactic
form `k' that accepts a single argument expression. The distinguishing
feature of _let/tc_ is that an application of a_let/tc_-bound
continuation is a syntactic form that evaluates its argument in tail
position with respect to the entire _let/tc_ expression.

Note that this means the argument expression is evaluated in the
captured continuation, i.e., after the jump occurs. This has important
consequences for side effects performed by the argument expression.
See the examples for a demonstration.

The syntactic form `k' is in scope for the evaluation of the body
expressions. It accepts exactly one argument expression.

Note also that continuations captured by _let/tc_ receive exactly one
value if invoked via the syntactic form `k', but may receive any
number of values if evaluation of the body does not invoke the
captured continuation.

> (push-begin e1 e2 ...)

A syntax for evaluating a sequence of expressions, like Scheme's
primitive BEGIN, but without preserving tail context. In particular,
the last expression of _push-begin_ is NOT in tail position with
respect to the containing expression.

The value of a _push-begin_ expression, like BEGIN, is the value of
the last expression in the sequence.

The expressions of a _push-begin_ may evaluate to multiple values (or
no values).

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

EXAMPLES -------------------------------------------------------------

(define (current-continuation-mark-list key-v)
  (continuation-mark-set->list (current-continuation-marks) key-v))

(define (countdown n)
  (with-continuation-mark 'countdown n
    (let/ec return
      (if (zero? n)
          (return (current-continuation-mark-list 'countdown))
          (return (countdown (sub1 n)))))))

> (countdown 10)
(0 1 2 3 4 5 6 7 8 9 10)

(define (countdown* n)
  (with-continuation-mark 'countdown n
    (let/tc return
      (if (zero? n)
          (return (current-continuation-mark-list 'countdown))
          (return (countdown* (sub1 n)))))))

> (countdown 10)
(0)

;; The argument to a let/tc continuation is evaluated after the jump
;; occurs.

> (with-continuation-mark 'jump 'after
    (let/ec k
      (with-continuation-mark 'jump 'before
        (k (current-continuation-mark-list 'jump)))))
(before)

> (with-continuation-mark 'jump 'after
    (let/tc k
      (with-continuation-mark 'jump 'before
        (k (current-continuation-mark-list 'jump)))))
(after)

> (with-handlers ([exn? (lambda (exn) 'uncaught)])
    (let/ec k
      (with-handlers ([exn? (lambda (exn) 'caught)])
        (k (error 'stop)))))
caught

> (with-handlers ([exn? (lambda (exn) 'uncaught)])
    (let/tc k
      (with-handlers ([exn? (lambda (exn) 'caught)])
        (k (error 'stop)))))
uncaught