gpt4 book ai didi

racket - 为什么这个生成器实现在 Racket 中不起作用?

转载 作者:行者123 更新时间:2023-12-05 05:42:10 26 4
gpt4 key购买 nike

我正在尝试使用 call/cc 在 racket 中实现生成器,到目前为止我有这段代码

(define (foo2)
(define (g abort)
(define-syntax-rule
(yield x)
(call/cc (lambda (k)
(set! g k)
(abort x))))
(yield 'foo)
(yield 'bar)
(yield 'tar)
(abort 'end))
(thunk (call/cc g)))

如果我在 REPL 中使用它,它似乎工作正常

foo.rkt> (define g (foo2))
foo.rkt> (g)
'foo
foo.rkt> (g)
'bar
foo.rkt> (g)
'tar
foo.rkt> (g)
'end
foo.rkt> (g)
'end
foo.rkt>

但是如果我尝试在列表中调用 g,它会挂起,我不知道发生了什么

foo.rkt> (define g (foo2))
foo.rkt> (list (g) (g) (g))
;; prompt is not released

这是怎么回事?我的生成器实现哪里错了?

最佳答案

什么是 (list (g) (g) (g))?嗯,在 CPS 中基本上是这样的:

(g& (lambda (g1) ; continuation g1 
(g& (lambda (g2)
(g& (lambda (g3)
(list& g1 g2 g3 halt))))

你正在替换 g&,但是你们所有人 yield 共享相同的初始 abort 这是继续 g1并且您永远不会到达延续 g2,因为每次调用 abort 时,您都会运行延续 g1。如果您单步执行,您会注意到此延续得到了所有的产出值,但最终它调用了 abort。即使您删除了最后一个调用,它也始终会在您的表达式中调用第二个 (g)

有助于了解call/cc&是这样的:

(define (call/cc& f cc)
(f (lambda (v ignored-cc)
(cc v))
cc))

现在 CPS 中的 g 看起来像这样。请注意,abort 是其中的自由变量,即使您替换 g&

,它们也是相同的
(define (g& abort cont)
(call/cc& (lambda (k cc)
(set!& g&
k
(lambda (undefined)
(abort 'foo cc))))
(lambda (ignored1)
(call/cc& (lambda (k cc)
(set!& g&
k
(lambda (undefined)
(abort 'bar cc))))
(lambda (ignored2)
(call/cc& (lambda (k cc)
(set!& g&
k
(lambda (undefined)
(abort 'tar cc))))
(lambda (ignored3)
(abort 'end cont)))))))))

作为修复,我想您需要控制设置为 g 的内容。例如。代替(set!g k) 可能是这样的:

(set! g (lambda (new-abort)
(set! abort new-abort)
(k 'ignored)))

然后列表表达式按预期工作。为什么它在 REPL 中起作用是由于 continuation prompts .

关于racket - 为什么这个生成器实现在 Racket 中不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72106367/

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