290 lines
8.7 KiB
Racket
290 lines
8.7 KiB
Racket
#lang scribble/doc
|
|
@(require (except-in "mz.rkt" set) (for-label racket/control))
|
|
|
|
@title{Additional Control Operators}
|
|
|
|
@note-lib-only[racket/control]
|
|
|
|
@(define control-eval
|
|
(let ([the-eval (make-base-eval)])
|
|
(the-eval '(require racket/control))
|
|
the-eval))
|
|
|
|
The @racket[racket/control] library provides various control operators
|
|
from the research literature on higher-order control operators, plus a
|
|
few extra convenience forms. These control operators are implemented
|
|
in terms of @racket[call-with-continuation-prompt],
|
|
@racket[call-with-composable-continuation], @|etc|, and they generally
|
|
work sensibly together. Many are redundant; for example,
|
|
@racket[reset] and @racket[prompt] are aliases.
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@defproc[(call/prompt
|
|
[proc procedure?]
|
|
[prompt-tag continuation-prompt-tag? (default-continuation-prompt-tag)]
|
|
[handler (or/c procedure? #f) #f]
|
|
[arg any/c] ...)
|
|
any]{
|
|
The @racket[call/prompt] binding is an alias for @racket[call-with-continuation-prompt].
|
|
}
|
|
|
|
@defproc[(abort/cc
|
|
[prompt-tag any/c]
|
|
[v any/c] ...)
|
|
any]{
|
|
The @racket[abort/cc] binding is an alias for @racket[abort-current-continuation].
|
|
}
|
|
|
|
@defproc[(call/comp
|
|
[proc (continuation? . -> . any)]
|
|
[prompt-tag continuation-prompt-tag? (default-continuation-prompt-tag)])
|
|
any]{
|
|
The @racket[call/comp] binding is an alias for @racket[call-with-composable-continuation].
|
|
}
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@defproc[(abort [v any/c] ...) any]{
|
|
|
|
Returns the @racket[v]s to a prompt using the default continuation
|
|
prompt tag and the default abort handler.
|
|
|
|
That is, @racket[(abort v ...)] is equivalent to
|
|
|
|
@racketblock[
|
|
(abort-current-continuation
|
|
(default-continuation-prompt-tag)
|
|
(lambda () (values v ...)))
|
|
]
|
|
|
|
@examples[#:eval control-eval
|
|
(prompt
|
|
(printf "start here\n")
|
|
(printf "answer is ~a\n" (+ 2 (abort 3))))
|
|
]}
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@deftogether[(
|
|
@defform*[[(% expr)
|
|
(% expr handler-expr)
|
|
(% expr handler-expr #:tag tag-expr)]]
|
|
@defproc[(fcontrol
|
|
[v any/c]
|
|
[#:tag prompt-tag (default-continuation-prompt-tag)])
|
|
any]
|
|
)]{
|
|
|
|
|
|
Sitaram's operators @cite["Sitaram93"].
|
|
|
|
The essential reduction rules are:
|
|
|
|
@racketblock[
|
|
(% _val proc) => _val
|
|
(% _E[(fcontrol _val)] _proc) => (_proc _val (lambda (_x) _E[_x]))
|
|
(code:comment @#,t{where @racket[_E] has no @racket[%]})
|
|
]
|
|
|
|
When @racket[handler-expr] is omitted, @racket[%] is the same as
|
|
@racket[prompt]. If @racket[prompt-tag] is provided, @racket[%]
|
|
uses specific prompt tags like @racket[prompt-at].
|
|
|
|
@examples[#:eval control-eval
|
|
(% (+ 2 (fcontrol 5))
|
|
(lambda (v k)
|
|
(k v)))
|
|
(% (+ 2 (fcontrol 5))
|
|
(lambda (v k)
|
|
v))
|
|
]}
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@deftogether[(
|
|
@defform[(prompt expr ...+)]
|
|
@defform[(control id expr ...+)]
|
|
)]{
|
|
|
|
Among the earliest operators for higher-order control
|
|
@cite["Felleisen88a" "Felleisen88" "Sitaram90"].
|
|
|
|
The essential reduction rules are:
|
|
@racketblock[
|
|
(prompt _val) => _val
|
|
(prompt _E[(control _k _expr)]) => (prompt ((lambda (_k) _expr)
|
|
(lambda (_v) _E[_v])))
|
|
(code:comment @#,t{where @racket[_E] has no @racket[prompt]})
|
|
]
|
|
|
|
@examples[#:eval control-eval
|
|
(prompt
|
|
(+ 2 (control k (k 5))))
|
|
(prompt
|
|
(+ 2 (control k 5)))
|
|
(prompt
|
|
(+ 2 (control k (+ 1 (control k1 (k1 6))))))
|
|
(prompt
|
|
(+ 2 (control k (+ 1 (control k1 (k 6))))))
|
|
(prompt
|
|
(+ 2 (control k (control k1 (control k2 (k2 6))))))
|
|
]}
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@deftogether[(
|
|
@defform[(prompt-at prompt-tag-expr expr ...+)]
|
|
@defform[(control-at prompt-tag-expr id expr ...+)]
|
|
)]{
|
|
|
|
Like @racket[prompt] and @racket[control], but using specific prompt
|
|
tags:
|
|
|
|
@racketblock[
|
|
(prompt-at _tag _val) => _val
|
|
(prompt-at _tag _E[(control-at _tag _k _expr)]) => (prompt-at _tag
|
|
((lambda (_k) _expr)
|
|
(lambda (_v) _E[_v])))
|
|
(code:comment @#,t{where @racket[_E] has no @racket[prompt-at] for @racket[_tag]})
|
|
]}
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@deftogether[(
|
|
@defform[(reset expr ...+)]
|
|
@defform[(shift id expr ...+)]
|
|
)]{
|
|
|
|
Danvy and Filinski's operators @cite["Danvy90"].
|
|
|
|
The essential reduction rules are:
|
|
|
|
@racketblock[
|
|
(reset _val) => _val
|
|
(reset _E[(shift _k _expr)]) => (reset ((lambda (_k) _expr)
|
|
(lambda (_v) (reset _E[_v]))))
|
|
(code:comment @#,t{where @racket[_E] has no @racket[reset]})
|
|
]
|
|
|
|
The @racket[reset] and @racket[prompt] forms are interchangeable.}
|
|
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@deftogether[(
|
|
@defform[(reset-at prompt-tag-expr expr ...+)]
|
|
@defform[(shift-at prompt-tag-expr identifier expr ...+)]
|
|
)]{
|
|
|
|
Like @racket[reset] and @racket[shift], but using the specified prompt
|
|
tags.}
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@deftogether[(
|
|
@defform[(prompt0 expr ...+)]
|
|
@defform[(reset0 expr ...+)]
|
|
@defform[(control0 id expr ...+)]
|
|
@defform[(shift0 id expr ...+)]
|
|
)]{
|
|
|
|
Generalizations of @racket[prompt], @|etc| @cite["Shan04"].
|
|
|
|
The essential reduction rules are:
|
|
|
|
@racketblock[
|
|
(prompt0 _val) => _val
|
|
(prompt0 _E[(control0 _k _expr)]) => ((lambda (_k) _expr)
|
|
(lambda (_v) _E[_v]))
|
|
(reset0 _val) => _val
|
|
(reset0 _E[(shift0 _k _expr)]) => ((lambda (_k) _expr)
|
|
(lambda (_v) (reset0 _E[_v])))
|
|
]
|
|
|
|
The @racket[reset0] and @racket[prompt0] forms are interchangeable.
|
|
Furthermore, the following reductions apply:
|
|
|
|
@racketblock[
|
|
(prompt _E[(control0 _k _expr)]) => (prompt ((lambda (_k) _expr)
|
|
(lambda (_v) _E[_v])))
|
|
(reset _E[(shift0 _k _expr)]) => (reset ((lambda (_k) _expr)
|
|
(lambda (_v) (reset0 _E[_v]))))
|
|
(prompt0 _E[(control _k _expr)]) => (prompt0 ((lambda (_k) expr)
|
|
(lambda (_v) _E[_v])))
|
|
(reset0 _E[(shift _k _expr)]) => (reset0 ((lambda (_k) expr)
|
|
(lambda (_v) (reset _E[_v]))))
|
|
]
|
|
|
|
That is, both the @racket[prompt]/@racket[reset] and
|
|
@racket[control]/@racket[shift] sites must agree for @racket[0]-like
|
|
behavior, otherwise the non-@racket[0] behavior applies.}
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@deftogether[(
|
|
@defform[(prompt0-at prompt-tag-expr expr ...+)]
|
|
@defform[(reset0-at prompt-tag-expr expr ...+)]
|
|
@defform[(control0-at prompt-tag-expr id expr ...+)]
|
|
@defform[(shift0-at prompt-tag-expr id expr ...+)]
|
|
)]{
|
|
|
|
Variants of @racket[prompt0], @|etc|, that accept a prompt tag.}
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@defproc[(spawn [proc ((any/c . -> . any) . -> . any)]) any]{
|
|
|
|
The operators of Hieb and Dybvig @cite["Hieb90"].
|
|
|
|
The essential reduction rules are:
|
|
|
|
@racketblock[
|
|
(prompt-at _tag _obj) => _obj
|
|
(spawn _proc) => (prompt _tag (_proc (lambda (_x) (abort _tag _x))))
|
|
(prompt-at _tag _E[(abort _tag _proc)])
|
|
=> (_proc (lambda (_x) (prompt-at _tag _E[_x])))
|
|
(code:comment @#,t{where @racket[_E] has no @racket[prompt-at] for @racket[_tag]})
|
|
]}
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@defproc[(splitter [proc (((-> any) . -> . any)
|
|
((continuation? . -> . any) . -> . any)
|
|
. -> . any)])
|
|
any]{
|
|
|
|
The operator of Queinnec and Serpette @cite["Queinnec91"].
|
|
|
|
The essential reduction rules are:
|
|
@racketblock[
|
|
(splitter _proc) => (prompt-at _tag
|
|
(_proc (lambda (_thunk)
|
|
(abort _tag _thunk))
|
|
(lambda (_proc)
|
|
(control0-at _tag _k (_proc _k)))))
|
|
(prompt-at _tag _E[(abort _tag _thunk)]) => (_thunk)
|
|
(code:comment @#,t{where @racket[_E] has no @racket[prompt-at] for @racket[_tag]})
|
|
(prompt-at _tag _E[(control0-at _tag _k _expr)]) => ((lambda (_k) _expr)
|
|
(lambda (_x) _E[_x]))
|
|
(code:comment @#,t{where @racket[_E] has no @racket[prompt-at] for @racket[_tag]})
|
|
]}
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@deftogether[(
|
|
@defproc[(new-prompt) any]
|
|
@defform[(set prompt-expr expr ...+)]
|
|
@defform[(cupto prompt-expr id expr ...+)]
|
|
)]{
|
|
|
|
The operators of Gunter et al. @cite["Gunter95"].
|
|
|
|
In this library, @racket[new-prompt] is an alias for
|
|
@racket[make-continuation-prompt-tag], @racket[set] is an alias for
|
|
@racket[prompt0-at], and @racket[cupto] is an alias for @racket[control0-at].
|
|
|
|
}
|
|
|
|
@close-eval[control-eval]
|