[plt-scheme] letrec and threads

From: Dimitris Vyzovitis (vyzo at media.mit.edu)
Date: Mon Feb 19 11:10:12 EST 2007

On Mon, 19 Feb 2007, Dimitris Vyzovitis wrote:

> And now the less simple case that results in undefined values:
> (define sch (make-channel))
> (define spawner
>   (thread
>    (lambda ()
>      (let lp ((thunk (channel-get sch)))
>           (thread thunk)
>           (lp (channel-get sch))))))
> (define (spawn thunk)
>   (channel-put sch thunk))

ok, this is wrong. spawn evaluates to void. Let me fix it:

(require (lib "list.ss" "srfi" "1"))
(define sch (make-channel))
(define spawner
   (lambda ()
     (let lp ((pend null))
          (apply sync
           (handle-evt sch
             (lambda (v)
               (let ((ch (car v))
                     (thr (thread (cdr v))))
                 (lp (cons (cons ch thr) pend)))))
           (map (lambda (e)
                  (handle-evt (channel-put-evt (car e) (cdr e))
                              (lambda (evt)
                                (lp (delete e pend eq?)))))

(define (spawn thunk)
  (let ((ch (make-channel)))
    (channel-put sch (cons ch thunk))
    (channel-get ch)))

(define (oops)
  (define (foo other ch)
    (channel-put ch other))
  (letrec ((ch1 (make-channel))
           (ch2 (make-channel))
           (foo1 (spawn (lambda () (foo foo2 ch1))))
           (foo2 (spawn (lambda () (foo foo1 ch2)))))
      (values (thread? (sync ch1)) (thread? (sync ch2)))))

And now we get:
> (oops)

I don't see this as a bug, it is to be expected with the standard
expansion of letrec to
(let (...
      (foo1 #<undefined>)
      (foo2 #<undefined>))
  (set! foo1 (spawn ...))
  (set! foo2 (spawn ...))

But it is still an interesting case of undefined behavior in the
presence of threads...

-- vyzo

Posted on the users mailing list.