#|
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)))))))