docs/docs/scheme-intro/continuations.md

Summary

Maintainability
Test Coverage
---
sidebar_position: 7
description: Powerful feature of Scheme that allow to add new control flows
---

# Continuations

## What is continuation?

In Scheme and Lisp a continuation is a thing that is waiting for an expression to be evaluated.

If you have code like this:

```scheme
(+ 1 2 <slot>)
```

and `<slot>` is an expression: (e.g.: `(/ 1 10)`)

```scheme
(+ 1 2 (/ 1 10))
```

then continuation for expression `(/ 1 10)` is `(+ 1 2 <slot>)`. Scheme is unique because it allows
to access continuations. They are first class objects like numbers or functions.

## Accessing current continuation

To access the current continuation for expression, you use `call-with-current-continuation` or its
abbreviation `call/cc`. The procedure `call/cc` accept a single procedure that get the continuation as
first argument:

```scheme
(call/cc (lambda (c)
           ...))
```

The continuation saved in `c` capture whole state of the Scheme interpreter. The continuation act as
a procedure that you can pass a single value to it and Scheme will jump in to the place where
continuation was captured with a given value.

## Calling continuations

You can save continuation inside a variable and call it later like a procedure.

```scheme
(define k #f)

(+ 1 (call/cc
       (lambda (continuation)
         (set! k continuation)
         2)))
;; ==> 3
(k 10)
;; ==> 11
```

Here when you call a continuation `k` with value 10 it restores the state in `(+ 1 <slot>)` and
execute that expression again with a value `10`.

The continuation act like a procedure and return `#t` with `procedure?` predicate:

```scheme
(define k (call/cc (lambda (c) c)))
(procedure? k)
;; ==> #t
```

## Early exit

The simple thing you can do with continuations is an early exit. Scheme doesn't have a return
expression, but with continuations you can add one.

```scheme
(define (find item lst)
  (call/cc (lambda (return)
             (let loop ((lst lst))
                (if (null? lst)
                    (return #f)
                    (if (equal? item (car lst))
                        (return lst)
                        (loop (cdr lst))))))))
```

You can even create abstrcation with anaphoric macro:

```scheme
(define-macro (alambda args . body)
  `(lambda ,args
     (call/cc (lambda (return)
                ,@body))))
```

and you can use this macro like normal `lambda`, but you have anaphoric `return` expression:

```scheme
(define exists? (alambda (item lst)
                         (for-each (lambda (x)
                                     (if (equal? x item)
                                         (return #t)))
                                   lst)
                         #f))

(exists? 'x '(a b c d e f))
;; ==> #f
(exists? 'd '(a b c d e f))
;; ==> #t
```

Here for-each always iterates over all elements, but with early exit it will return immediately when
found a value.

## Loops

You can create loops with continuations:

```scheme
(define (make-range from to)
  (call/cc
   (lambda (return)
     (let ((result '()))
       (let ((loop (call/cc (lambda (k) k))))
         (if (<= from to)
             (set! result (cons from result))
             (return (reverse result)))
         (set! from (+ from 1))
         (loop loop))))))

(make-range 1 10)
;; ==> (1 2 3 4 5 6 7 8 9 10)
```

The first continuation creates an early exit, like in the previous example. But the second call/cc use
identity function (it return continuation). Which means that the continuation is saved in a loop
variable. And each time it's called with `loop` as an argument, it's again assigned that
continuation to loop variable. This is required for the next loop.

## Generators

Some languages have generators and a `yield` keyword. In Scheme, you can create generators with
continuations.

```scheme
(define (make-coroutine-generator proc)
  (define return #f)
  (define resume #f)
  (define yield (lambda (v)
                  (call/cc (lambda (r)
                             (set! resume r)
                             (return v)))))
  (lambda ()
    (call/cc (lambda (cc)
               (set! return cc)
               (if resume
                   (resume (if #f #f))  ; void? or yield again?
                   (begin (proc yield)
                          (set! resume (lambda (v)
                                         (return (eof-object))))
                          (return (eof-object))))))))
```

The above example came from
[SRFI 158 example implementation](https://github.com/scheme-requests-for-implementation/srfi-158/blob/master/srfi-158-impl.scm#L77-L87).

The procedure `make-coroutine-generator` allows defining generators:

```scheme
(define counter (make-coroutine-generator
                 (lambda (yield)
                   (do ((i 0 (+ i 1)))
                     ((<= 3 i))
                     (yield i)))))

(counter) ;; ==> 0
(counter) ;; ==> 1
(counter) ;; ==> 2
(counter) ;; ==> #<eof>
```

With continuations, you can do a lot of cool new flow control structures.