Next: dynamic environment guard, Previous: dynamic environment parms, Up: dynamic environment [Index]
The dynamic environment is maintained by the standard function
dynamic-wind
, which has the arguments:
(dynamic-wind in-guard thunk out-guard)
the thunk in-guard is called every time the execution flow enters the dynamic extent of the call to thunk; the thunk out-guard is called every time the execution flow exits the dynamic extent of the call to thunk.
When we call dynamic-wind
: the in-guard and out-guard
thunks are pushed on a stack referenced by an internal Vicare
global variable. Whenever we save the current continuation by calling
call/cc
: such internal stack is stored in the state of the
created continuation.
We always create the dynamic extent of a function call by calling the function; then, by saving continuations, we can enter and exit the dynamic extent any number of times. Let’s try to understand what this means.
(import (vicare)) (with-result (dynamic-wind (lambda () (add-result 'in-guard)) (lambda () (add-result 'thunk) 1) (lambda () (add-result 'out-guard)))) ⇒ (1 (in-guard thunk out-guard))
(import (vicare)) (with-result (call/cc (lambda (escape) (dynamic-wind (lambda () (add-result 'in-guard)) (lambda () (add-result 'thunk-in) (escape 2) (add-result 'thunk-out) 1) (lambda () (add-result 'out-guard)))))) ⇒ (2 (in-guard thunk-in out-guard))
in this example thunk is called but it never performs a normal function return.
(import (vicare)) (with-result (call/cc (lambda (escape) (with-exception-handler (lambda (E) (add-result 'handler) (escape E)) (lambda () (dynamic-wind (lambda () (add-result 'in-guard)) (lambda () (add-result 'thunk-in) (raise 2) (add-result 'thunk-out) 1) (lambda () (add-result 'out-guard)))))))) ⇒ (2 (in-guard thunk-in handler out-guard))
(import (vicare)) (with-result (coroutine (lambda () (dynamic-wind (lambda () (add-result '(1 in-guard))) (lambda () (add-result '(1.1 thunk)) (yield) (add-result '(1.2 thunk)) (yield) (add-result '(1.3 thunk))) (lambda () (add-result '(1 out-guard)))))) (coroutine (lambda () (dynamic-wind (lambda () (add-result '(2 in-guard))) (lambda () (add-result '(2.1 thunk)) (yield) (add-result '(2.2 thunk)) (yield) (add-result '(2.3 thunk))) (lambda () (add-result '(2 out-guard)))))) (finish-coroutines) 1) ⇒ (1 ((1 in-guard) (1.1 thunk) (1 out-guard) (2 in-guard) (2.1 thunk) (2 out-guard) (1 in-guard) (1.2 thunk) (1 out-guard) (2 in-guard) (2.2 thunk) (2 out-guard) (1 in-guard) (1.3 thunk) (1 out-guard) (2 in-guard) (2.3 thunk) (2 out-guard)))
call/cc
was called.
(import (vicare)) (with-result (dynamic-wind (lambda () (add-result 'outer-in-guard)) (lambda () (add-result 'outer-thunk-in) (call/cc (lambda (escape) (dynamic-wind (lambda () (add-result 'inner-in-guard)) (lambda () (add-result 'inner-thunk-in) (escape) (add-result 'inner-thunk-out)) (lambda () (add-result 'inner-out-guard))))) (add-result 'outer-thunk-out) 1) (lambda () (add-result 'outer-out-guard)))) ⇒ (1 (outer-in-guard outer-thunk-in inner-in-guard inner-thunk-in inner-out-guard outer-thunk-out outer-out-guard))
About exiting from the dynamic extent of a function call, we must acknowledge that:
(define (fun escape) (do-something) (escape 123) (do-something)) (call/cc fun)
(define (fun) (do-something) ;;Does not exit the dynamic extent of the call to FUN. (raise 123))
guard
are executed outside the extent of the guard
body.
Next: dynamic environment guard, Previous: dynamic environment parms, Up: dynamic environment [Index]