相当于Scheme在Ruby中的动态风

时间:2010-10-06 18:21:38

标签: ruby scheme continuations

Ruby有连续性......它是否有像Scheme这样的dynamic-wind结构?

1 个答案:

答案 0 :(得分: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

(要使用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

因此,正常运行的dynamic_wind实现将确保在调用continuation时将$stdout设置回/dev/null流,以便在{{1}的所有实例中运行时,确实没有显示该文本。