Implement yield and send in Scheme

前端 未结 3 1776
你的背包
你的背包 2020-12-06 03:17

I\'m trying to port yield and yield from from Python to Scheme.

Here is an implementation I\'ve done:

(define (coroutine ro         


        
3条回答
  •  独厮守ぢ
    2020-12-06 03:57

    Something like this:

    (define (make-generator procedure)
      (define last-return values)
      (define last-value #f)
      (define (last-continuation _) 
        (let ((result (procedure yield))) 
          (last-return result)))
    
      (define (yield value)
        (call/cc (lambda (continuation)
                   (set! last-continuation continuation)
                   (set! last-value value)
                   (last-return value))))
    
      (lambda args
        (call/cc (lambda (return)
                   (set! last-return return)
                   (if (null? args)
                       (last-continuation last-value)
                       (apply last-continuation args))))))
    

    Used like this:

    (define test 
     (make-generator
       (lambda (collect)
         (collect 1)
         (collect 5)
         (collect 10)
         #f)))
    
    (test) ; ==> 1
    (test) ; ==> 5
    (test) ; ==> 10
    (test) ; ==> #f (procedure finished)
    

    Now we can wrap the internals into a macro:

    (define-syntax (define-coroutine stx)
      (syntax-case stx ()
        ((_ (name . args) . body )
         #`(define (name . args)
             (make-generator 
              (lambda (#,(datum->syntax stx 'yield))
                . body))))))
    

    Notice that define-coroutine is implemented using syntax-case since we need to make yield unhygienic.

    (define-coroutine (countdown-from n)
      (let loop ((n n))
        (if (= n 0)
            0
            (loop (- (yield n) 1)))))
    
    (define countdown-from-10 (countdown-from 10))
    
    (define (ignore procedure)
      (lambda ignore
        (procedure)))
    
    (map (ignore countdown-from-10) '(1 1 1 1 1 1)) ; ==> (10 9 8 7 6 5)
    
    ;; reset
    (countdown-from-10 10)  ; ==> 9
    (countdown-from-10)     ; ==> 8
    ;; reset again
    (countdown-from-10 100) ; ==> 99
    

提交回复
热议问题