相当于Scheme在Ruby中的动态风

Cla*_*diu 2 ruby scheme continuations

Ruby有延续......它有dynamic-windScheme这样的结构吗?

Chr*_*ung 5

[这个答案是由计划程序员编写的(OP之前曾在此处提出其他方案问题,因此这是一个安全的选择).如果你在这里因为你是一个没有Scheme背景的Ruby程序员,请阅读脚注以获取一些上下文.:-)]

MRI没有(见下文); 如果MRI没有,这意味着即使另一个实现提供它,也没有可移植的方式来使用任何这样的功能.

我确实检查了MRI 1.9.1源代码.在任何情况下,这里都有一些代码来证明即使正常的展开保护(ensure)也不能正确地连续MRI(用1.8.7和1.9.1测试).(它与JRuby(我用1.5测试)一起工作正常,所以它表明它是一个特定于实现的东西.但请注意,JRuby只提供转义延续,而不是通用的.)

callcc do |cc|
  begin
    puts 'Body'
    cc.call
  ensure
    puts 'Ensure'
  end
end
Run Code Online (Sandbox Code Playgroud)

(要使用MRI 1.9+进行测试,您需要使用该-rcontinuation选项运行,或者放在require 'continuation'文件的顶部.)


对于不知道是什么的读者来说dynamic-wind,这是一种指定在被覆盖的代码退出时运行的代码(非常类似ensure)的方法,以及在重新输入所覆盖的代码时要运行的代码.(当您call/cc在覆盖的代码中使用时,可能会发生这种情况,并在退出覆盖的代码后调用continuation对象.)

完全做作的例子:

def dynamic_wind pre, post, &block
  raise 'Replace this with a real implementation, kthx'
end

def redirect_stdout port, &block
  saved = $stdout
  set_port = lambda {$stdout = port}
  reset_port = lambda {$stdout = saved}
  dynamic_wind set_port, reset_port, &block
end

cc = nil
# cheap way to nuke all the output ;-)
File.open '/dev/null' do |null|
  redirect_stdout null do
    callcc {|cc|}
    puts 'This should not be shown'
  end
  puts 'This should be shown'
  cc.call
end
Run Code Online (Sandbox Code Playgroud)

因此,正常运行的dynamic_wind实现将确保在调用continuation时$stdout将其设置回流/dev/null,以便在puts 'This should not be shown'运行的所有实例中,确实不显示该文本.