# Continuations issue - Shift vs Control

**URL:** <https://racket.discourse.group/t/continuations-issue-shift-vs-control/4083>\
**Category:** Questions & Answers\
**Created:** [January 17, 2026, 11:03am UTC](https://racket.discourse.group/t/continuations-issue-shift-vs-control/4083 "2026-01-17T11:03:36Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![matteo-daddio](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/matteo-daddio/32/1245_2.png) [@matteo-daddio](https://racket.discourse.group/u/matteo-daddio)\
**Post date:** [January 17, 2026, 11:03am UTC](https://racket.discourse.group/t/continuations-issue-shift-vs-control/4083/1 "2026-01-17T11:03:36Z")

</div>

Hello,

I need to work with continuations. I read the documentation about it and is very well written. Only the documentation about the racket/control library is a bit cryptic. I needed to ask the AI for help and I think I’ve spotted a bug about the difference between the shift and control operators.

The difference between shift and control is that shift adds a reset automatically:

```scheme
;control
(prompt val) => val
(prompt E[(control k expr)]) => (prompt ((lambda (k) expr)
                                         (lambda (v) E[v])))

;reset
(reset val) => val
(reset E[(shift k expr)]) => (reset ((lambda (k) expr)
                                     (lambda (v) (reset E[v]))))

```

But in this example there’s no difference:

```scheme
(reset (+ 1 (shift k1 
              (k1 (+ 10 (shift k2 100))))))
              
;=> 100
              
(prompt (+ 1 (control k1 
               (k1 (+ 10 (control k2 100))))))
               
;=> 100

```

I think this is a bug. If I add a reset manually the output changes:

```scheme
(reset (+ 1 (shift k1 
              (k1 (reset (+ 10 (shift k2 100)))))))
              
;=> 101
              
(prompt (+ 1 (control k1 
               (k1 (+ 10 (control k2 100))))))
               
;=> 100

```

If this is a bug I don’t know where to report it.

Matteo

---

<div class="post-metadata">

**Author:** ![ryanc](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/ryanc/32/71_2.png) [@ryanc](https://racket.discourse.group/u/ryanc)\
**Post date:** [January 17, 2026, 12:08pm UTC](https://racket.discourse.group/t/continuations-issue-shift-vs-control/4083/2 "2026-01-17T12:08:28Z")

</div>

It's not a bug. If I had to guess, I think your mistake is forgetting that `k1` is "just" a function, and the arguments to a function are evaluated before the function is called. So yes, `k1` contains its own `reset` wrapper, but it doesn't affect the evaluation of the second `shift`.

Here is how the first example reduces, roughly:

```scheme
(reset (+ 1 (shift k1
              (k1 (+ 10 (shift k2 100))))))

;; Reduce the shift (k1).
;; E = (+ 1 [])
;; expr = (k1 (+ 10 (shift k2 100)))

(reset (let ([k1 (lambda (v1) (reset (+ 1 v1)))])
         (k1 (+ 10 (shift k2 100)))))

;; Reduce the shift (k2). (The body of the let is a function call,
;; and we must evaluate the argument before calling the function.)
;; E = (let ([k1 ___]) (k1 (+ 10 [])))
;; expr = 100

(reset (let ([k2 (lambda (v2)
                   (reset (let ([k1 (lambda (v1) (reset (+ 1 v1)))])
                            (k1 (+ 10 v2)))))])
         100))

;; Delete unused let bindings.

(reset 100)

;; Reduce the reset.

100

```

And here is how to the second example reduces:

```scheme
(reset (+ 1 (shift k1
              (k1 (reset (+ 10 (shift k2 100)))))))

;; Reduce the shift (k1).
;; E = (+ 1 [])
;; expr = (k1 (reset (+ 10 (shift k2 100))))

(reset (let ([k1 (lambda (v1) (reset (+ 1 v1)))])
         (k1 (reset (+ 10 (shift k2 100))))))

;; Reduce the shift (k2). (The body of the let is a function call, 
;; so we must evaluate the argument before calling the function.)
;; E = (+ 10 [])
;; expr = 100
;; within (reset (let ([k1 ___]) (k1 [])))

(reset (let ([k1 (lambda (v1) (reset (+ 1 v1)))])
         (k1 (reset (let ([k2 (lambda (v2) (reset (+ 10 v2)))])
                      100)))))

;; Delete the unused let-binding of k2.

(reset (let ([k1 (lambda (v1) (reset (+ 1 v1)))])
         (k1 (reset 100))))

;; Reduce the reset.

(reset (let ([k1 (lambda (v1) (reset (+ 1 v1)))])
         (k1 100)))

;; Apply k1.

(reset (reset (+ 1 100)))

;; Apply +.

(reset (reset 101))

;; Reduce the reset.

(reset 101)

;; Reduce the reset.

101

```

To make the intermediate steps easier to read, I've written the result of a shift reduction using `let` and kept the `let` around instead of doing substitution eagerly. I hope it's clear.

---

<div class="post-metadata">

**Author:** ![matteo-daddio](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/matteo-daddio/32/1245_2.png) [@matteo-daddio](https://racket.discourse.group/u/matteo-daddio)\
**Post date:** [January 17, 2026, 1:07pm UTC](https://racket.discourse.group/t/continuations-issue-shift-vs-control/4083/3 "2026-01-17T13:07:49Z")

</div>

Thank you very much.

Can you make an example where the differences between shift and control appear?

Matteo

---

<div class="post-metadata">

**Author:** ![EmEf](https://avatars.discourse-cdn.com/v4/letter/e/53a042/32.png) [@EmEf](https://racket.discourse.group/u/EmEf)\
**Post date:** [January 17, 2026, 3:08pm UTC](https://racket.discourse.group/t/continuations-issue-shift-vs-control/4083/4 "2026-01-17T15:08:49Z")

</div>

In a shell:

```scheme
$ racket

> (require racket/control)

```

then

```scheme
> ((lambda (x) (shift c (add1 (c (c 0))))) (shift k (k (k 0))))

```

versus

```scheme
> ((lambda (x) (control c (add1 (c (c 0))))) (control k (k (k 0))))

```

(Be ready to ctrl-c. And you may wish to add `println` in some places.)

;; - - -

-- `control` reifies the continuation as a mathematical function, modulo the effects that the programmer "bakes in".

-- `shift` reifies the continuation as a procedure with a control (delimiter) effect added, plus the effects that the programmer bakes in.

---

<div class="post-metadata">

**Author:** ![shawnw](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/shawnw/32/1031_2.png) [@shawnw](https://racket.discourse.group/u/shawnw)\
**Post date:** [January 31, 2026, 12:40pm UTC](https://racket.discourse.group/t/continuations-issue-shift-vs-control/4083/5 "2026-01-31T12:40:51Z")

</div>

See [this Stack Overflow Q&A](https://stackoverflow.com/questions/64688165/examples-of-the-difference-between-prompt-control-and-shift-reset) for another demonstration of the difference.

(Personally, in anything complicated I've tried, the extra `reset` that `shift` adds messes things up from what I think they should be, but `prompt`/`control` usually works, or the lower-level operations they're both built on. No good examples handy, alas.)
