# How can I keep a REPL alive during \`read-eval-print-loop\` + \`with-handlers\` + a contract violation?

**URL:** <https://racket.discourse.group/t/how-can-i-keep-a-repl-alive-during-read-eval-print-loop-with-handlers-a-contract-violation/1126>\
**Category:** Questions & Answers\
**Tags:** repl\
**Created:** [July 6, 2022, 9:03pm UTC](https://racket.discourse.group/t/how-can-i-keep-a-repl-alive-during-read-eval-print-loop-with-handlers-a-contract-violation/1126 "2022-07-06T21:03:52Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![benknoble](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/benknoble/32/16_2.png) [@benknoble](https://racket.discourse.group/u/benknoble)\
**Post date:** [July 6, 2022, 9:03pm UTC](https://racket.discourse.group/t/how-can-i-keep-a-repl-alive-during-read-eval-print-loop-with-handlers-a-contract-violation/1126/1 "2022-07-06T21:03:52Z")

</div>

I have a program that starts a REPL via `(read-eval-print-loop)` that happens to be dynamically inside a `with-handlers` clause. And I noticed something equivalent to the following that might be related to `error-escape-handler`. In both of the following two cases, enter `(+ 1 #f)` at the REPL, which generates a contract failure:

1. `racket -e '(read-eval-print-loop)'` [Notice the REPL keeps going.]
2. `racket -e '(with-handlers ([exn:fail? (const 1)]) (read-eval-print-loop))'` [Notice the 1 is returned and the REPL dies.]

Now, you may say "that's perfectly obvious behavior," and it _is_. But I would love to have a way for, say, only contract failures (`exn:fail:contract?`), or really any failure at my discretion, to behave the usual way and not kill the REPL-inside-`with-handlers`, so that the REPL state is unaffected like it would normally be. How can I do this?

---

<div class="post-metadata">

**Author:** ![sorawee](https://avatars.discourse-cdn.com/v4/letter/s/ea5d25/32.png) [@sorawee](https://racket.discourse.group/u/sorawee)\
**Post date:** [July 6, 2022, 9:54pm UTC](https://racket.discourse.group/t/how-can-i-keep-a-repl-alive-during-read-eval-print-loop-with-handlers-a-contract-violation/1126/2 "2022-07-06T21:54:03Z")

</div>

I got this working, but there might be a better way:

```scheme
;; file.rktl
(let ([this-eval (current-eval)])
  (define handler (uncaught-exception-handler))
  (define (pls-exit e)
    (parameterize ([error-escape-handler (λ () (exit 1))])
      (handler e)))
  (parameterize ([current-eval (λ (v)
                                 (with-handlers ([exn:fail:contract? handler]
                                                 [(const #t) pls-exit])
                                   (this-eval v)))])
    (read-eval-print-loop)))

```

```scheme
$ racket -f file.rktl
> (+ 1 1)
2
> (+ #f)
+: contract violation
  expected: number?
  given: #f
  context...:
   body of top-level
...
> (raise 1)
uncaught exception: 1
$

```

---

<div class="post-metadata">

**Author:** ![sorawee](https://avatars.discourse-cdn.com/v4/letter/s/ea5d25/32.png) [@sorawee](https://racket.discourse.group/u/sorawee)\
**Post date:** [July 6, 2022, 10:02pm UTC](https://racket.discourse.group/t/how-can-i-keep-a-repl-alive-during-read-eval-print-loop-with-handlers-a-contract-violation/1126/3 "2022-07-06T22:02:58Z")

</div>

Perhaps this is better? Idk.

```scheme
(let ([this-eval (current-eval)])
  (define (the-eval v)
    (call-with-exception-handler
     (λ (e)
       (cond
         [(exn:fail:contract? e) e]
         [else
          (error-escape-handler (λ () (exit 1)))
          e]))
     (λ () (this-eval v))))

  (parameterize ([current-eval the-eval])
    (read-eval-print-loop)))

```

---

<div class="post-metadata">

**Author:** ![benknoble](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/benknoble/32/16_2.png) [@benknoble](https://racket.discourse.group/u/benknoble)\
**Post date:** [July 7, 2022, 3:35pm UTC](https://racket.discourse.group/t/how-can-i-keep-a-repl-alive-during-read-eval-print-loop-with-handlers-a-contract-violation/1126/4 "2022-07-07T15:35:53Z")

</div>

Sorawee's solutions are interesting, and I haven't fully digested them, but I ended up with a slightly simpler solution: run the `(read-eval-print-loop)` outside of the `with-handlers` 🙂

The `with-handlers` is handy for my programs commands to report errors as possible bugs; however, for the REPL command, I can just let things be.

---

<div class="post-metadata">

**Author:** ![mflatt](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/mflatt/32/6_2.png) [@mflatt](https://racket.discourse.group/u/mflatt)\
**Post date:** [July 7, 2022, 4:27pm UTC](https://racket.discourse.group/t/how-can-i-keep-a-repl-alive-during-read-eval-print-loop-with-handlers-a-contract-violation/1126/5 "2022-07-07T16:27:33Z")

</div>

The `read-eval-print-loop` function keeps going after exceptions because

- it wraps evaluation with a default prompt, and
- the default unhandled-exception handler aborts to the default prompt.

If you want to escape further than the default prompt for a certain exceptions, then `call-with-continuation-prompt` is the right idea. For the kinds of exceptions where you want to stop the REPL, escape to an enclosing prompt. For other kinds of exceptions, just pass them along to the enclosing exception handler, which likely invokes the uncaught-exception handler:

```scheme
(let ([tag (make-continuation-prompt-tag)])
  (call-with-continuation-prompt
   (lambda ()
     (call-with-exception-handler
      (λ (e)
        (cond
          [(exn:fail:contract? e)
           (abort-current-continuation tag e)]
          [else e]))
      (λ () (read-eval-print-loop))))
   tag
   (lambda (e) (raise e))))

```
