Continuations and call/cc
Continuations can implement exceptions, generators, coroutines, backtracking (amb), cooperative threads, and web frameworks that keep state across requests (Racket's web server).
Delimited continuations (shift/reset, Racket's call-with-composable-continuation, control/prompt) capture only part of the stack and are easier to reason about.
;; A continuation represents "the rest of the computation" at some point
(+ 1 (call/cc (lambda (k) (k 41)))) ; 42: k returns 41 to the waiting (+ 1 _)
;; Early exit from a loop
(define (find-first pred lst)
(call/cc
(lambda (return)
(for-each (lambda (x) (when (pred x) (return x))) lst)
#f)))
(find-first negative? '(1 2 -3 4 -5)) ; -3
;; Continuations can be saved and re-entered later (re-entry at the top level
;; behaves differently across implementations, so the generator below keeps it local)
;; Generators with continuations
(define (make-generator lst)
(define return #f) ; where to deliver the next value (updated on every call)
(define resume ; where to continue the traversal
(lambda (ignored)
(for-each (lambda (x)
(call/cc (lambda (k)
(set! resume k)
(return x))))
lst)
(return 'done)))
(lambda ()
(call/cc (lambda (r)
(set! return r)
(resume #f)))))
(define g (make-generator '(a b c)))
(g) (g) (g) (g) ; a b c done#lang racket
(require racket/control)
(+ 1 (reset (+ 10 (shift k (k (k 100)))))) ; 121: k = (λ (v) (+ 10 v)), applied twice → 120, plus 1