#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 @racketmodname[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 interchangeable.
 
@; ----------------------------------------------------------------------

@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 @racketidfont{0}-like
behavior, otherwise the non-@racketidfont{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[
(spawn _proc)
  => (prompt/spawn _tag
       (_proc (lambda (_proc) (abort/spawn _tag _proc))))
  (code:comment @#,t{where @racket[_tag] is a freshly generated prompt tag})
(prompt/spawn _tag _val)
  => _val
(prompt/spawn _tag _E[(abort/spawn _tag _proc)])
  => (_proc (lambda (_x) (prompt/spawn _tag _E[_x])))
  (code:comment @#,t{where @racket[_E] has no @racket[prompt/spawn] 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/splitter _tag
       (_proc (lambda (_thunk) (abort/splitter _tag _thunk))
              (lambda (_proc) (control0/splitter _tag _k (_proc _k)))))
  (code:comment @#,t{where @racket[_tag] is a freshly generated prompt tag})
(prompt/splitter _tag _val)
  => _val
(prompt/splitter _tag _E[(abort/splitter _tag _thunk)])
  => (_thunk)
  (code:comment @#,t{where @racket[_E] has no @racket[prompt/splitter] for @racket[_tag]})
(prompt/splitter _tag _E[(control0/splitter _tag _k _expr)])
  => ((lambda (_k) _expr)
      (lambda (_x) _E[_x]))
  (code:comment @#,t{where @racket[_E] has no @racket[prompt/splitter] for @racket[_tag]})
]}

@; ----------------------------------------------------------------------

@deftogether[(
@defproc*[([(new-prompt) continuation-prompt-tag?]
           [(new-prompt [name symbol?]) continuation-prompt-tag?])]
@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].

@history[#:changed "8.11.0.3" @elem{The @racket[new-prompt] function is now
          really an alias for @racket[make-continuation-prompt-tag].}]
}

@close-eval[control-eval]
