Ruby 的产量特性与计算机科学的关系

发布于 2024-07-17 12:18:00 字数 70 浏览 8 评论 0原文

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

I recently discovered Ruby's blocks and yielding features, and I was wondering: where does this fit in terms of computer science theory? Is it a functional programming technique, or something more specific?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

爱你不解释 2024-07-24 12:18:00

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

是的,块是一种函数式编程特性,尽管 Ruby 并不是一种真正的函数式语言。 事实上,Ruby 使用 lambda 方法来创建块对象,该方法借用自 Lisp 创建匿名函数的语法——这就是块。 从计算机科学的角度来看,Ruby 的块(以及 Lisp 的 lambda 函数)是闭包。 在 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]

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

Ruby's yield is not an iterator like in C# and Python. yield itself is actually a really simple concept once you understand how blocks work in Ruby.

Yes, blocks are a functional programming feature, even though Ruby is not properly a functional language. In fact, Ruby uses the method lambda to create block objects, which is borrowed from Lisp's syntax for creating anonymous functions — which is what blocks are. From a computer science standpoint, Ruby's blocks (and Lisp's lambda functions) are closures. In Ruby, methods usually take only one block. (You can pass more, but it's awkward.)

The yield keyword in Ruby is just a way of calling a block that's been given to a method. These two examples are equivalent:

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

In the first case, we're just assuming there's a block and say to call it. In the other, Ruby wraps the block in an object and passes it as an argument. The first is more efficient and readable, but they're effectively the same. You'd call either one like this:

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

And it would print the value that wound up getting assigned to @my_var. (OK, so that's a completely stupid function, but I think you get the idea.)

Blocks are used for a lot of things in Ruby. Almost every place you'd use a loop in a language like Java, it's replaced in Ruby with methods that take blocks. For example,

[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]

As Andrew noted, it's also commonly used for opening files and many other places. Basically anytime you have a standard function that could use some custom logic (like sorting an array or processing a file), you'll use a block. There are other uses too, but this answer is already so long I'm afraid it will cause heart attacks in readers with weaker constitutions. Hopefully this clears up the confusion on this topic.

安人多梦 2024-07-24 12:18:00

除了循环之外,yield 和 block 还有更多内容。

系列枚举可枚举有一系列你可以用枚举做的事情,比如询问如果某个陈述对于组中的任何成员都成立,或者对于所有成员都成立,或者搜索满足特定条件的任何或所有成员。

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

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

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

随便谷歌一下,并没有找到一篇关于 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

There's more to yield and blocks than mere looping.

The series Enumerating enumerable has a series of things you can do with enumerations, such as asking if a statement is true for any member of a group, or if it's true for all the members, or searching for any or all members meeting a certain condition.

Blocks are also useful for variable scope. Rather than merely being convenient, it can help with good design. For example, the code

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

ensures that the file stream is closed when you're finished with it, even if an exception occurs, and that the variable is out of scope once you're finished with it.

A casual google didn't come up with a good blog post about blocks and yields in ruby. I don't know why.

Response to comment:

I suspect it gets closed because of the block ending, not because the variable goes out of scope.

My understanding is that nothing special happens when the last variable pointing to an object goes out of scope, apart from that object being eligible for garbage collection. I don't know how to confirm this, though.

I can show that the file object gets closed before it gets garbage collected, which usually doesn't happen immediately. In the following example, you can see that a file object is closed in the second puts statement, but it hasn't been garbage collected.

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
泪意 2024-07-24 12:18:00

我认为 yield 语句源自 CLU语言。 我一直想知道 Tron 中的角色是否也以 CLU 命名......

I think the yield statement originated from the CLU language. I always wonder if the character from Tron was named after CLU too....

冰葑 2024-07-24 12:18:00

我认为 'coroutine' 是您正在寻找的关键字。

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

计算和信息科学领域的产出:

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

I think 'coroutine' is the keyword you're looking for.

E.g. http://en.wikipedia.org/wiki/Yield

Yield in computing and information science:

  • in computer science, a point of return (and re-entry) of a coroutine
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文