racket/collects/2htdp/private/launch-many-worlds.rkt
Eli Barzilay 5aca765989 racket' -> racket/base' switches in htdp' and 2htdp'.
All of these look safe.  Also, see comment in `2htdp/batch-io' about the
splitting thing (which should probably be revised with the extensions to
`racket/string').
2012-11-06 13:29:09 -05:00

57 lines
1.8 KiB
Racket

#lang racket/base
(require racket/list racket/function racket/gui
mzlib/etc htdp/error)
(provide
;; (launch-many-worlds e1 ... e2)
;; run expressions e1 through e2 in parallel,
;; produce all values
launch-many-worlds
;; launch-many-worlds/proc : (-> Any) *-> [Listof Any]
launch-many-worlds/proc)
(define-syntax-rule
(launch-many-worlds e ...)
(launch-many-worlds* (lambda () e) ...))
(define (launch-many-worlds/proc . loth)
;; check args
(for ([th loth][i (in-naturals 1)])
(check-proc 'launch-many-worlds/proc th 0 i "no arguments"))
(apply launch-many-worlds* loth))
;; [Listof (-> X)] ->* X ...
(define (launch-many-worlds* . loth)
(let* ([c* (make-custodian)]
[ch (make-channel)]
[pu (curry channel-put ch)]
[th (map (lambda (th i)
(parameterize ([current-custodian c*])
(rec t
(thread
(lambda ()
(with-handlers ((exn? pu)) (pu (list i t (th)))))))))
loth
(build-list (length loth) (lambda (i) i)))])
(letrec ([L (lambda (th r*)
(if (null? th)
(apply values (map third (sort r* < #:key first)))
(sync
(handle-evt
ch
(lambda (x)
(if (exn? x)
(begin
(custodian-shutdown-all c*)
(raise x))
(L (remq (second x) th) (cons x r*))))))))])
(with-handlers ((exn:break? (lambda (xn) (custodian-shutdown-all c*))))
(L th '())))))
;; some silly tests
; (launch-many-worlds 1 2 3)
; (launch-many-worlds 1 (let loop ([n 100]) (printf "~s\n" n) (sleep 1) (loop n)) 3)