为什么此发电机实现在球拍中不起作用?

发布于 2025-01-26 04:01:44 字数 723 浏览 4 评论 0 原文

我正在尝试使用 call/cc 在球拍中实现发电机,如果我在repl中使用它,我已经有了

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

代码

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> 

此 列表,它挂起,我不知道发生了什么事

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

?我的发电机实施是错误的?

I'm trying to implement generators in racket using call/cc, I have this code so far

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

If I play with this in the REPL it seems to be working correctly

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> 

But if I try to call g inside a list, it hangs and I have no idea what is happening

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

What is going on? Where my generator implementation is wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

忘年祭陌 2025-02-02 04:01:44

什么是(列表(g)(g)(g))?好吧,基本上是在CPS中:

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

您要替换 g& ,但是你们所有人 yarts 共享相同的初始中止 continuation > g1 ,您将永远无法连续 g2 ,因为每次中止被称为您运行持续 g1 。如果您逐步完成,您会注意到此延续将得到所有收益率值,但最终将调用中止。即使您删除了最后一个通话,它也会始终在表达式中拨打第二个(g)

它有助于知道呼叫/CC& 是:

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

现在,CPS中的 g 看起来像这样。请注意,中止是其中的免费变量,即使您替换 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!gk)也许是这样的:

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

然后列表表达式按预期工作。为什么它在repl中工作的原因是继续提示

What is (list (g) (g) (g))? Well it is basically this in CPS:

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

You are replacing g&, but all of you yield share the same initial abort which is continuation g1 and you will never ever reach continuation g2 since every time abort is called you run continuation g1. If you step through you'll notice that this continuation gets fed all the yield values but eventually it calls abort. Even if you remove the last call it will always call the second (g) in your expression.

It helps to know call/cc& is this:

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

Now g in CPS would look something like this. Notice the abort are free variables in there and they will be the same even if you replace 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)))))))))

As a fix I guess you need to control what you set as g. Eg. instead of
(set! g k) something like this perhaps:

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

Then the list expression works as expected. Why it worked in the REPL is due to continuation prompts.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文