【问题标题】:Ruby's yield feature in relation to computer scienceRuby 与计算机科学相关的 yield 特性
【发布时间】:2010-10-20 07:58:11
【问题描述】:

我最近发现了 Ruby 的块和产生功能,我想知道:这在计算机科学理论方面适合什么?它是一种函数式编程技术,还是更具体的技术?

【问题讨论】:

    标签: ruby functional-programming yield


    【解决方案1】:

    Ruby 的 yield 不像 C# 和 Python 中的迭代器。 yield 本身实际上是一个非常简单的概念,一旦您了解了块在 Ruby 中的工作原理。

    是的,块是一种函数式编程特性,尽管 Ruby 并不是一种适当的函数式语言。事实上,Ruby 使用 lambda 方法创建块对象,这是从 Lisp 用于创建匿名函数的语法中借用的——这就是块的含义。从计算机科学的角度来看,Ruby 的块(和 Lisp 的 lambda 函数)是closures。在 Ruby 中,方法通常只占用一个块。 (你可以通过更多,但是很尴尬。)

    Ruby 中的yield 关键字只是一种调用已赋予方法的块的方式。这两个例子是等价的:

    def with_log
      output = yield # We're calling our block here with yield
      puts "Returned value is #{output}"
    end
    
    def with_log(&stuff_to_do) # the & tells Ruby to convert into
                               # an object without calling lambda
      output = stuff_to_do.call # We're explicitly calling the block here
      puts "Returned value is #{output}"
    end
    

    在第一种情况下,我们只是假设有一个块并说要调用它。另一方面,Ruby 将块包装在一个对象中并将其作为参数传递。第一个更高效和可读,但它们实际上是相同的。你可以这样称呼任何一个:

    with_log do
      a = 5
      other_num = gets.to_i
      @my_var = a + other_num
    end
    

    它会打印最终分配给@my_var 的值。 (好吧,这是一个完全愚蠢的功能,但我想你明白了。)

    块在 Ruby 中用于很多事情。几乎每一个你会在像 Java 这样的语言中使用循环的地方,它在 Ruby 中都被替换为带块的方法。例如,

    [1,2,3].each {|value| print value} # prints "123"
    [1,2,3].map {|value| 2**value}    # returns [2, 4, 8]
    [1,2,3].reject {|value| value % 2 == 0} # returns [1, 3]
    

    正如 Andrew 所说,它也常用于打开文件和许多其他地方。基本上只要你有一个可以使用一些自定义逻辑的标准函数(比如排序数组或处理文件),你就会使用一个块。还有其他用处,不过这个答案已经这么长了,恐怕会导致体质较弱的读者心脏病发作。希望这能消除对该主题的困惑。

    【讨论】:

    • 谢谢,这更有意义,它与我迄今为止所学到的关于块的知识更相关。
    【解决方案2】:

    yield 和 blocks 不仅仅是循环。

    Enumerating enumerable 系列有一系列可以用枚举做的事情,例如询问某个陈述是否对组中的任何成员为真,或者对所有成员是否为真,或者搜索任何或所有成员满足一定条件。

    块对于变量范围也很有用。它不仅方便,还可以帮助进行良好的设计。比如代码

    File.open("filename", "w") do |f|
      f.puts "text"
    end
    

    确保文件流在您完成后关闭,即使发生异常,并且一旦您完成该变量就超出范围。

    一个随便的 google 没有想出一篇关于 ruby​​ 块和产量的好博文。我不知道为什么。

    对评论的回应

    我怀疑它被关闭是因为块结束,而不是因为变量超出范围。

    我的理解是,当指向对象的最后一个变量超出范围时,除了该对象符合垃圾回收条件外,没有什么特别的事情发生。不过,我不知道如何确认。

    我可以证明文件对象在被垃圾收集之前就被关闭了,这通常不会立即发生。在下面的示例中,您可以看到在第二个 puts 语句中关闭了一个文件对象,但它还没有被垃圾回收。

    g = nil
    File.open("/dev/null") do |f|
      puts f.inspect # #<File:/dev/null>
      puts f.object_id # Some number like 70233884832420
      g = f
    end
    puts g.inspect # #<File:/dev/null (closed)>
    puts g.object_id # The exact same number as the one printed out above,
      # indicating that g points to the exact same object that f pointed to
    

    【讨论】:

    • 这如何确保文件在完成后关闭?当块结束并且f 超出范围时,Ruby 会自动关闭它?
    • @aidan File#open 方法在使用块调用时,将在块完成后关闭创建的文件句柄。
    • 感谢您的澄清!
    【解决方案3】:

    我认为yield 语句起源于CLU 语言。我一直想知道《创》中的角色是否也以 CLU 命名....

    【讨论】:

    • 致原发帖人​​:Daniel 的回答中,您可能想在 Google 上搜索“协程”——这是 CLU 使用 yield 实现的基本“计算机科学”概念。
    【解决方案4】:

    我认为'coroutine' 是您要查找的关键字。

    例如http://en.wikipedia.org/wiki/Yield

    计算和信息科学领域的成果:

    • 在计算机科学中,协程的返回(和重新进入)点

    【讨论】:

    • 感谢@itowlson,他在另一个答案的评论中同时提到了“协程”。
    • Ruby 中yield 关键字的使用与通常的CS 定义中的yield 没有任何关系。这只是一个子程序调用。实际上,如果将匿名块分配给变量,则可以只使用 call 而不是 yield。
    • 这不是Ruby中的用法。
    猜你喜欢
    • 2013-01-29
    • 1970-01-01
    • 1970-01-01
    • 2018-04-02
    • 2017-07-07
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    相关资源
    最近更新 更多