Scheme中的call/cc与Python和JavaScript中的yield是一样的吗?

cma*_*mal 4 scheme yield generator

call/ccScheme 中的内容与yieldPython 和 JavaScript 中的内容相同吗?

我不清楚发电机。在我看来,yield它赋予了一种语言轻松生成迭代器的能力。但我不确定我是否正确。

在Scheme中是否有与其他语言call/cc相关的东西?yield如果是这样,它们是同一件事还是有什么区别?

谢谢!

Syl*_*ter 5

call/cc是比生成器更通用的语言功能。因此你可以用 来制作生成器call/cc,但不能call/cc用生成器来制作。

如果您有一个计算值并在其他地方使用这些值的程序,那么它基本上是一台步进机。人们可能会认为它是一个程序,每个步骤都有一个函数,其余步骤有一个延续。因此:

(+ (* 3 4) (* 5 6))
Run Code Online (Sandbox Code Playgroud)

可以解释为:

((lambda (k)
  (k* 3 4 (lambda (v34)
            (k* 5 6 (lambda (v56)
                      (k+ v34 v56 k)))))
 halt)
Run Code Online (Sandbox Code Playgroud)

k 前缀仅表明它是原语的 CPS 版本。因此,他们将最后一个参数作为带有结果的函数调用。还要注意的是,Scheme 中未定义的求值顺序实际上是在此重写中选择的。用这美丽的语言来说call/cc就是这样:

(define (kcall/cc kfn k)
  (kfn (lambda (value ignored-continuation)
         (k value))
       k))
Run Code Online (Sandbox Code Playgroud)

所以当你这样做时:

(+ (* 3 4) (call/cc (lambda (exit) (* 5 (exit 6))))) 
; ==> 18
Run Code Online (Sandbox Code Playgroud)

在幕后发生这种情况:

((lambda (k)
  (k* 3 4 (lambda (v34)
            (kcall/cc (lambda (exit k)
                        (exit 6 (lambda (v6)
                                 (k* 5 v6 k)))
                      k))))
 halt)
Run Code Online (Sandbox Code Playgroud)

通过使用替换,我们可以证明这实际上完全符合预期。由于调用了退出函数,因此永远不会调用原始延续,因此计算被取消。与call/cc给我们提供这种看似不明显的延续相比,CPS 中没有什么魔法。因此, 的大部分魔力call/cc都在编译器阶段。

(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)
Run Code Online (Sandbox Code Playgroud)

人们可能会创建一个宏来使语法更加相似,但它只是在此之上的糖。

有关更多示例,我喜欢 Matt Mights 页面,其中有很多有关如何使用延续的示例。