6.8. kink/CONTROL

This module provides some basic control structures.

6.8.1. CONTROL.while($continue? $body)

`while` calls $body repeatedly while $continue? returns true.

`while` first calls $continue? with no args. If $continue? returns true, `while` calls $body with no args, then goes back to the beginning. If $continue? returns false, `while` returns.

Preconditions

$continue? must be a thunk that returns a `bool`.

$body must be a thunk.

Example

6.8.2. CONTROL.try($body $returned_cont $raised_cont)

`try` invokes $body with no args.

If the invocation of $body returns, `try` tail-calls $returned_cont with the result of $body.

If the invocation of $body raises an exception, `try` tail-calls $raised_cont with the exception.

Preconditions

$body must be a thunk.

$returned_cont must be a function which takes one arg.

$raised_cont must be a function which takes an `exception`.

Example

6.8.3. CONTROL.with_return($body)

`with_return` calls $body with a function $return. In the invocation of $body, you can call $return with a thunk $exit_cont. When $return is called, the invocation of $body is aborted on the spot, and `with_return` tail-calls $exit_cont.

If the invocation of $body reaches the end without calling $return, `with_return` raises an exception.

Precondition

$body must be a function which takes a function $return.

Example

The recursive call of `gcd` does not consume the stack, because it is called at the tail context of `with_return`, which is also the tail context of `gcd`. So it is a tail recursion.

Note that there is a much simpler version of `gcd` without `with_return`:

Example: nested invocations

6.8.4. CONTROL.with_finally($body)

`with_finally` calls $body with a function $finally. In the invocation of $body, you can call $finally an arbitrary number of times with a thunk $cleanup. $cleanup is guaranteed to be called in the following situations:

(1) When the invocation of $body returns

(2) When the invocation of $body is jumped out by $return function of CONTROL.with_return

(3) When the invocation of $body raises an exception

If $finally is called `n` times, with thunks $cleanup_1, $cleanup_2 ,,, $cleanup_n in this order, the thunks are guaranteed to be called in the reverse order: $cleanup_n ,,, $cleanup_2, $cleanup_1.

You must not jump out from the invocation of $cleanup by CONTROL.with_return.

Result

(1) When the invocation of $body returns

If no cleanup thunks raise an exception, `with_finally` returns the value returned by the invocation of $body.

If one or more cleanup thunks raise an exception, they are chained as a single exception, and `with_finally` raises the chained exception.

(2) When the invocation of $body is jumped out by $return function of CONTROL.with_return

If no cleanup thunks raise an exception, `with_finally` restarts the jumping out.

If one or more cleanup thunks raise an exception, they are chained as a single exception, and `with_finally` raises the chained exception.

(3) When the invocation of $body raises an exception

If no cleanup thunks raise an exception, `with_finally` raises the exception raised by $body.

If one or more cleanup thunks raise an exception, they are added to the chain of the exception raised by $body, and `with_finally` raises the chained exception.

Precondition

$body must be a function which takes a function $finally.

Example

6.8.5. CONTROL.with_return_finally($body)

`with_return_finally` calls $body with $return and $finally.

It is equivalent to nesting `with_return` and `with_finally` like this:

$return aborts the invocation of $body on the spot, and `with_return_finally` tail-calls the thunk passed to $return.

$finally registers a cleanup thunk. See `with_finally` for details on cleanup semantics.

Precondition

$body must be a function which takes $return and $finally.

Example