Robust coroutines/generators for R6RS
- From: Derick Eddington <derick.eddington@xxxxxxxxx>
- Date: Sat, 5 Jul 2008 05:54:48 -0700 (PDT)
Hi all,
I've made a coroutines library, and I'm wondering if there are any
problems with it or if it could be improved. I made it handle issues
that were not obvious to me at first: the dynamic environment of
raised exceptions and recursive or concurrent use screwing it up.
[I hope Google Groups formats this right.]
=====================================================================
(library (xitomatl coroutines)
(export
make-coroutine
coroutine
case-coroutine
define-coroutine
&coroutine-finished?
&coroutine-finished-coroutine)
(import
(rnrs)
(only (xitomatl define extras) define/?/AV))
;;; Inspired by Will Farr's generators example:
;;; http://wmfarr.blogspot.com/2006/08/one-more-example-of-python-generators.html
;;;
;;; NOTE: These coroutines are not thread/engine safe,
;;; and a coroutine must not call itself.
(define-condition-type &coroutine-finished &condition
make-&coroutine-finished &coroutine-finished?
(coroutine &coroutine-finished-coroutine))
(define/?/AV (make-coroutine [make-proc procedure?])
(letrec*
([yield
(lambda args
(call/cc
(lambda (k)
(set! resume k)
(return (lambda () (apply values args))))))]
[resume
(let ([proc (make-proc yield)])
(unless (procedure? proc)
(AV "make-proc did not return a procedure" proc))
;; The initial resume isn't actually "resuming". It's
what starts
;; the coroutine by calling the procedure which contains
the body
;; of the coroutine.
(lambda args
(with-exception-handler
(lambda (ex)
;; Doing this makes the dynamic environment (e.g.
the
;; exception handlers) of the raise of the
exception
;; from inside proc be that of the current
invocation of
;; the coroutine. Otherwise, it would always be
that
;; of the first invocation.
(return (lambda () (raise ex))))
(lambda () (apply proc args)))
(let ([gf (make-&coroutine-finished coroutine)])
;; Set resume to this so that proc is not re-entered
if the
;; coroutine is invoked again after proc has returned.
(set! resume (lambda args (return (lambda () (raise
gf)))))
;; Raise in the dynamic environment of the current
;; invocation of the coroutine.
(return (lambda () (raise gf))))))]
[return #f]
[coroutine
(lambda args
(when return
(assertion-violation 'coroutine
"illegal recursive or concurrent call" coroutine))
(let ([return-proc (call/cc
(lambda (k)
(set! return k)
(apply resume args)))])
(set! return #f)
(return-proc)))])
coroutine))
(define-syntax case-coroutine/lexical-context
(lambda (stx)
(syntax-case stx ()
[(_ ctxt [frmls b0 b ...] ...)
(with-syntax ([yield (datum->syntax #'ctxt 'yield)])
#'(make-coroutine
(lambda (yield)
(case-lambda [frmls b0 b ...] ...))))])))
;;; NOTE: Matching arguments and selecting a clause only happens
;; the first time the coroutine is called.
(define-syntax case-coroutine
(lambda (stx)
(syntax-case stx ()
[(ctxt [frmls b0 b ...] ...)
#'(case-coroutine/lexical-context ctxt [frmls b0
b ...] ...)])))
(define-syntax coroutine
(lambda (stx)
(syntax-case stx ()
[(ctxt frmls b0 b ...)
#'(case-coroutine/lexical-context ctxt [frmls b0 b ...])])))
(define-syntax define-coroutine
(lambda (stx)
(syntax-case stx ()
[(_ (name . frmls) b0 b ...)
(identifier? #'name)
#'(define name
(case-coroutine/lexical-context name [frmls b0
b ...]))])))
)
=====================================================================
Python-style generators can be made like:
(define (PyG x)
(coroutine ()
(yield x)
(yield x)))
Tests for this library and the (xitomatl define extras) library can be
found at:
https://code.launchpad.net/~derick-eddington/ikarus-libraries/xitomatl
[Ikarus and PLT are currently the only implementations that can run
it.]
Thanks for any feedback.
--
: Derick
----------------------------------------------------------------
.
- Follow-Ups:
- Re: Robust coroutines/generators for R6RS
- From: Derick Eddington
- Re: Robust coroutines/generators for R6RS
- Prev by Date: Functional letrec
- Next by Date: SRFI 98: An interface to access environment variables.
- Previous by thread: Functional letrec
- Next by thread: Re: Robust coroutines/generators for R6RS
- Index(es):
Relevant Pages
|