I have my toy evaluator. I do not allow my evaluator to change parameters. Therefore I run the evaluator proper in a thread. I tried call-with-parameterization, but to no avail. I want ports opened by expressions passed to the evaluator to be closed when the evaluator returns or is halted by an exception. I want threads started by expressions passed to the evaluator to be killed when the evaluator returns or is halted by an exception. The same for other stuff. To accomplish this I have the code shown below. Without a custodian and custodian-shutdown ports are not closed and threads are not killed after a break or an exception. I wonder, can't this be done in a simpler way? Of course, I could use procedure exit, but this disables the interactions window too. How to kill all without killing the interactions window?
#lang racket/base (define evaluator (λ exprs (let* ((custodian (make-custodian)) (thread-exn #f) (always (λ x #t)) ; Catch all, non exceptions and breaks included. (shutdown (λ () (custodian-shutdown-all custodian))) (thread-exn #f) (thread-handler (λ (exn) (set! thread-exn exn))) (handler (λ (exn) (shutdown) (eprintf "Shutted down.~n") (if (exn? exn) (raise exn) (error 'evaluator "raised: ~s" exn)))) ; Simplified: Racket's eval instead of my own eval. (namespace (make-base-namespace)) (*eval (λ (expr) (writeln (eval expr namespace))))) (parameterize* ((current-custodian custodian)) (with-handlers* ((always handler)) (let* ((vals null) (thrd (thread (λ () (with-handlers* ((always thread-handler)) (call-with-values (λ () (for-each *eval exprs)) (λ x (set! vals x)))))))) (thread-wait thrd) (when thread-exn (raise thread-exn)) (shutdown) (apply values vals)))))))