Racket协同例程实现中的死锁

时间:2018-08-18 16:07:10

标签: functional-programming scheme racket coroutine continuations

作为一个帮助我理解Racket延续性的项目,我决定尝试编写一个不使用可变变量或全局变量的协同例程实现。到目前为止,这是我所拥有的,但是似乎最终陷入了某种僵局。我缺少明显的东西吗?

#!/usr/bin/env racket

#lang racket

(define (make-proc-args args)
  (let/cc cc
    (cons cc args)))

(define (fork proc)
  (let ([current (make-proc-args '())])
    (proc current)))

(define (yield to args)
  (let ([current (make-proc-args args)])
    ((car to) current)))

(define c
  (fork
    (lambda (p)
      (let loop ([i 0]
                 [parent p])
        (unless (> i 10)
          (loop (+ i 1) (yield parent (list i))))))))

(let loop ([child c])
  (println (car child))
  (loop (yield child '())))

1 个答案:

答案 0 :(得分:1)

(define (make-proc-args args)
  (let/cc cc
    (cons cc args)))

当被调用时,它作为对象返回其延续。如果您看这段代码:

(define (fork proc)
  (let ([current (make-proc-args '())])
    (proc current)))

(make-proc-args '())的延续是绑定了let和被调用current的{​​{1}}的应用。在以下情况下:

proc

这意味着(fork (lambda (p) (let loop ([i 0] [parent p]) (unless (> i 10) (loop (+ i 1) (yield parent (list i))))))) 将返回时间并调用,并且(yield parent (list i))将再次被调用。.以(proc current)i开头的租赁。 0的继续存储,对吗?错了!

yield

捕获的连续性是(define (yield to args) (let ([current (make-proc-args args)]) ((car to) current))) ,碰巧一次又一次地相同。

解决此问题的最简单方法是使延续不调用存储的延续,因为它是自己的延续。因此,您需要执行以下操作:

((car to) current)

请注意,在这两种情况下,延续都是(define (fork proc) (let/cc cc (let ([current (cons cc '())]) (proc current)))) (define (yield to args) (let/cc cc (let ([current (cons cc args)]) ((car to) current)))) yield自然返回时发生的情况,而不是fork的正文完成时发生的情况。

也知道延续是在顶层定界的,所以您也许应该在let块中测试所有代码,以捕获由于延续在顶层表现不同而可能带来的错误。不允许使用let作为顶层,但是如果将其放在define中,则会得到let作为#<void>的最后一个值,因为那是值{{1} }形式,而不是您期望的成对。

child

此打印:

define

最后一条提示。也许您应该为延续对象或至少抽象的结构?