gpt4 book ai didi

scheme - 实现 yield 并在 Scheme 中发送

转载 作者:行者123 更新时间:2023-12-04 23:44:59 25 4
gpt4 key购买 nike

我正在尝试移植 yieldyield from从 Python 到 Scheme。

这是我完成的一个实现:

(define (coroutine routine)
(let ((current routine)
(status 'new))
(lambda* (#:optional value)
(let ((continuation-and-value
(call/cc (lambda (return)
(let ((returner
(lambda (value)
(call/cc (lambda (next)
(return (cons next value)))))))
(if (equal? status 'new)
(begin
(set! status 'running)
(current returner))
(current (cons value returner)))
(set! status 'dead))))))
(if (pair? continuation-and-value)
(begin (set! current (car continuation-and-value))
(cdr continuation-and-value))
continuation-and-value)))))

这个实现的问题在于它必须被调用的方式看起来不像 Python 的 yield .
(define why (call/cc (lambda (yield)
(format #t "love me or leave me!")
(yield "I leave!")
;; the program never reach this part
(format #t "it probably left :("))))
(format #t "return actually populates WHY variable\n")
(format #t "WHY: ~a\n")

除其他外,每次我需要重新启动协程时,我 必须 let全新 return变量能够 exit协程。基本上,我觉得语法太冗长了。还有其他语法更简洁的吗?

应该可以到 yield send协程的值。以下是必须如何使用协程的示例:
(define-coroutine (zrange start step)
"compute a range of values starting a START with STEP between
each value. The coroutine must be restarted with 0 or more, which
is added to the step"
(let loop ((n start))
(loop (+ n step (yield n)))))


(coroutine-map (zrange 0 10) '(1 100 1000 10000 100000))
;; => 0 110 1120 11130 111140

在上面, 1被忽略然后 100 , 1000send到发电机。我已经基于@sylwester 代码完成了一个实现,但是我在使用宏时遇到了麻烦:
(define (make-generator procedure)
(define last-return #f)
(define last-value #f)
(define last-continuation (lambda (_) (procedure yield)))

(define (return value)
(newline)(display "fuuu")(newline)
(call/cc (lambda (continuation)
(set! last-continuation continuation)
(set! last-value value)
(last-return value))))
(lambda* (. rest) ; ignore arguments
(call/cc (lambda (yield)
(set! last-return yield)
(apply last-continuation rest)))))

(define-syntax define-coroutine
(syntax-rules ()
((_ (name args ...) body ...)
(define (name args ...)

(make-generator
(lambda (yield)
body ...))))))

(define-coroutine (zrange start step)
(let loop ((n start))
(loop (+ n step (yield n)))))

(display (map (zrange 0 10) '(1 100 1000 10000 100000)))

最佳答案

像这样的东西:

(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))))))

像这样使用:

(define test 
(make-generator
(lambda (collect)
(collect 1)
(collect 5)
(collect 10)
#f)))

(test) ; ==> 1
(test) ; ==> 5
(test) ; ==> 10
(test) ; ==> #f (procedure finished)

现在我们可以将内部组件包装成一个宏:

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

请注意 define-coroutine使用语法案例实现,因为我们需要制作 yield不卫生。

(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

关于scheme - 实现 yield 并在 Scheme 中发送,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30614788/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com