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]