【问题标题】:Equivalent of Scheme's dynamic-wind in RubyRuby 中 Scheme 的 dynamic-wind 等价物
【发布时间】:2011-04-21 23:57:39
【问题描述】:

Ruby 有延续...它有像 Scheme 这样的 dynamic-wind 构造吗?

【问题讨论】:

    标签: ruby scheme continuations


    【解决方案1】:

    [这个答案是为 Scheme 程序员写的(OP 之前在这里问过其他 Scheme 问题,所以这是一个安全的选择)。如果您是因为没有 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,并在被覆盖的代码退出后调用延续对象时,就会发生这种情况。)

    完全人为的例子:

    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 实现将确保$stdout 在调用延续时被设置回/dev/null 流,因此在运行puts 'This should not be shown' 的所有实例中,该文本是确实没有显示。

    【讨论】:

      猜你喜欢
      • 2011-02-12
      • 2012-04-07
      • 1970-01-01
      • 1970-01-01
      • 2011-07-11
      • 2016-06-21
      • 2010-09-20
      • 1970-01-01
      • 2015-01-07
      相关资源
      最近更新 更多