Implement yield and send in Scheme

前端 未结 3 1781
你的背包
你的背包 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 04:04

    Kudos to @Sylwester for a great answer.

    The difficult part is making yield available to the generator function. datum->syntax creates a syntax object, and requires you to provide another syntax object from which the context for the new object is taken. In this case, we can use stx which has the same context as the function passed into the macro.

    If people find it helpful, I use a simpler version:

    (define-syntax (set-continuation! stx)
      "Simplifies the common continuation idiom
        (call/cc (λ (k) (set! name k) ))"
      (syntax-case stx ()
        [(_ name . body)
         #`(call/cc (λ (k)
                      (set! name k)
                      . body))]))
    
    (define-syntax (make-generator stx)
      "Creates a Python-like generator. 
       Functions passed in can use the `yield` keyword to return values 
       while temporarily suspending operation and returning to where they left off
       the next time they are called."
      (syntax-case stx ()
        [(_ fn)
         #`(let ((resume #f)
                 (break #f))
             (define #,(datum->syntax stx 'yield)
               (λ (v)
                 (set-continuation! resume
                   (break v))))
             (λ ()
               (if resume
                   (resume #f)
                   (set-continuation! break
                     (fn)
                     'done))))]))
    

    An example of its usage:

    (define countdown
      (make-generator
       (λ ()
         (for ([n (range 5 0 -1)])
               (yield n)))))
    
    (countdown)
    => 5
    ...
    (countdown)
    => 1
    (countdown)
    => 'done
    (countdown)
    => 'done
    

提交回复
热议问题