gpt4 book ai didi

ruby - ruby 中的 callcc 导致无限循环?

转载 作者:数据小太阳 更新时间:2023-10-29 08:02:47 25 4
gpt4 key购买 nike

我正在尝试复习类幻灯片。该代码应该打印一次“早期工作”,然后打印两次“后期工作”(您可以设置后期工作的重复次数)。但是我想知道为什么这段代码不起作用,我该如何修改代码?从现在开始,代码将生成“稍后工作”的无限循环,而不是 2(应该是)

require 'continuation'
def work
p "early work"
here = callcc {|here| here}
p "later work"
return here
end

def rework(k)
entry = work
k.times do |i|
entry.call(entry)
end
end

rework(2)

最佳答案

代码不起作用,因为 k.times 中的循环计数器被卡住了。每次调用 entry.call(entry) 都会将程序倒回到 callcc 返回时。于是callcc又返回了,后面的工作又发生了,work又返回了,k.times又开始了。当 k.times 启动时,它将其循环计数器重置为零。无限循环是因为循环计数器始终为零。

要修复程序,我们必须继续循环,而不是重新启动它。最好的解决方法是使用纤程,但首先,我尝试使用延续。这是在我的机器上运行的版本:

require 'continuation'
def work
p "early work"
here = callcc {|here| here}
p "later work"
return here
end

class Integer
def my_times
i = 0
while i < self
yield i
i += 1
end
end
end

def rework(k)
entry = nil
k.my_times do |i|
if i == 0
entry = work
else
entry.call(entry)
end
end
end

rework(2)

我通过在循环内调用 work 来修复控制流。当 work 再次返回时,我不会重置循环计数器。

我还定义了我自己的 Integer#my_times 并且不使用 Ruby 的 Integer#times。如果我将代码从 k.my_times 改回 k.times,循环计数器会再次卡住。这暴露了 Ruby 中延续对象的问题。

当延续倒带程序时,它可能倒带或保留局部变量的值。我的程序假定 entry.call 保留循环计数器。 Matz 的 Ruby 实现在 Integer#my_times 中保留循环计数器,但在 Integer#times 中倒回循环计数器。这是我的程序无法使用 Integer#times 的唯一原因。

MRI 似乎在 C 代码(如 Integer#times)中倒带局部变量,但在 Ruby 代码中保留局部变量(如 Integer#my_times)。这会造成循环计数器和其他局部变量的困惑。 Ruby 没有解决这个问题,但会针对 callcc 发出警告。 Ruby 说,警告:callcc 已过时;改用光纤

这是使用光纤的程序:

def work
p "early work"
here = Fiber.new do
while true
p "later work"
Fiber.yield
end
end
here.resume
return here
end

def rework(k)
entry = nil
k.times do |i|
if i == 0
entry = work
else
entry.resume
end
end
end

rework(2)

关于ruby - ruby 中的 callcc 导致无限循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40709030/

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