# Shift vs Control difference - an example

**URL:** <https://racket.discourse.group/t/shift-vs-control-difference-an-example/4286>\
**Category:** Show & Tell\
**Created:** [June 17, 2026, 9:25pm UTC](https://racket.discourse.group/t/shift-vs-control-difference-an-example/4286 "2026-06-17T21:25:15Z")\
**Posts on this page:** 2\
**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:** [June 17, 2026, 9:25pm UTC](https://racket.discourse.group/t/shift-vs-control-difference-an-example/4286/1 "2026-06-17T21:25:15Z")

</div>

Hello,

I don’t know if this is well known or not, but after some reasoning I found an interesting example about the difference between `shift` and `control`.

I asked the AI to make an example about delimited continuations and the result is this:

```scheme
#lang racket

(require racket/control)

(define (amb choices)
  (control cont
    (for-each (lambda (x) 
                (prompt (cont x)))
              choices)))

;; A helper to force backtracking
(define (backtrack) (abort 'fail))

(define (find-pair sum-target)
  (reset
   (let ([x (amb '(1 2 3 4 5 6))]
         [y (amb '(1 2 3 4 5 6))])
     (if (and (= (+ x y) sum-target))
         (display (list x y))
         (backtrack))))) ; Try the next combination

(find-pair 7)

=> (1 6)(2 5)(3 4)(4 3)(5 2)(6 1)

```

It uses `control` and `abort` to develop a backtrack algorithm.

Now let’s change `control` with `shift` (I didn’t change `prompt` with `reset` because they are interchangeable):

```scheme
#lang racket

(require racket/control)

(define (amb choices)
  (shift cont
    (for-each (lambda (x) 
                (prompt (cont x)))
              choices)))

;; A helper to force backtracking
(define (backtrack) (abort 'fail))

(define (find-pair sum-target)
  (reset
   (let ([x (amb '(1 2 3 4 5 6))]
         [y (amb '(1 2 3 4 5 6))])
     (if (and (= (+ x y) sum-target))
         (display (list x y))
         (backtrack))))) ; Try the next combination

(find-pair 7)

=> (1 6)(2 5)(3 4)(4 3)(5 2)(6 1)

```

The result is the same, but what if I remove `prompt`?

Here I removed `prompt` from the `control` version:

```scheme
#lang racket

(require racket/control)

(define (amb choices)
  (control cont
    (for-each (lambda (x) 
                (cont x))
              choices)))

;; A helper to force backtracking
(define (backtrack) (abort 'fail))

(define (find-pair sum-target)
  ...)

(find-pair 7)

=> 'fail

```

The result is a failure.

But if I remove `prompt` from the `shift` version:

```scheme
#lang racket

(require racket/control)

(define (amb choices)
  (shift cont
    (for-each (lambda (x) 
                (cont x))
              choices)))

;; A helper to force backtracking
(define (backtrack) (abort 'fail))

(define (find-pair sum-target)
  ...)

(find-pair 7)

=> (1 6)(2 5)(3 4)(4 3)(5 2)(6 1)

```

It works, because `shift` adds a `prompt` when calls the continuation.

I managed to find a concise example:

```scheme
#lang racket

(require racket/control)

(prompt (shift cont
          (+ (cont '())
             (cont '())
             (cont '())))
        (abort 1))

(prompt (control cont
                 (+ (cont '())
                    (cont '())
                    (cont '())))
        (abort 1))
          
(prompt (control cont
                 (+ (prompt (cont '()))
                    (prompt (cont '()))
                    (prompt (cont '()))))
        (abort 1))

=> 3
   1
   3

```

It's possible to use `control` and `shift` instead of `abort`:

```scheme
#lang racket

(require racket/control)

(prompt (shift cont
          (+ (cont '())
             (cont '())
             (cont '())))
        (shift c 1))

(prompt (control cont
                 (+ (cont '())
                    (cont '())
                    (cont '())))
        (control c 1))
          
(prompt (control cont
                 (+ (prompt (cont '()))
                    (prompt (cont '()))
                    (prompt (cont '()))))
        (control c 1))

=> 3
   1
   3

```

But I think `abort` is clearer.

`Shift` is more elegant and concise, but perhaps `control` is more explicit and clear. It’s possible to use both, they work properly, It’s a matter of taste.

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:** [June 17, 2026, 9:45pm UTC](https://racket.discourse.group/t/shift-vs-control-difference-an-example/4286/2 "2026-06-17T21:45:10Z")

</div>

As you point out, `shift` sets up an internal prompt when it reifies the delimited continuation. Ergo it's not a matter of taste -- the two constructs have a different semantics.

One way to understand this is that control turns the delimited continuation into a plain function, assuming the language itself is functional. By contrast, `shift` adds the delimiter and hence its reified continuation is inherently effectful i.e. has an effect on continuation manipulations.

But yes, the two are close when it comes to pragmatics ("use in context") and you can often exchange one for the other.
