比较 Ruby 中的两个 lambda/Proc

发布于 2024-09-10 03:02:25 字数 1293 浏览 1 评论 0原文

这让我发疯,我在四处寻找之后才在这里发帖。

我想知道指向同一个 Proc 的两个变量是否指向同一个 Proc。 我确信这一定是我没有得到的东西,例如为什么所有这些都返回 false?

class LambdaFunctions
  def self.LambdaFunction1
    lambda { |t| t ** 2}
  end
end

a = LambdaFunctions.LambdaFunction1
b = LambdaFunctions.LambdaFunction1

puts LambdaFunctions.LambdaFunction1
puts a
puts b

puts a == b
puts a === b
puts a.eql?(b)
puts a.equal?(b)
puts a == LambdaFunctions.LambdaFunction1
puts a === LambdaFunctions.LambdaFunction1
puts a.eql?(LambdaFunctions.LambdaFunction1)
puts a.equal?(LambdaFunctions.LambdaFunction1)

谢谢马克,你说得更清楚了。 以前它每次都返回新对象,所以相等吗?函数永远不会返回 true。这两个 lambda 函数在功能上相同,但不是同一个对象。 因此,如果您创建一个版本,然后在方法中将其返回,您就可以测试它的身份。 以下内容更有意义并且按我的预期工作。

class LambdaFunctions

  @lambda1 = lambda { |t| t ** 2}
  @lambda2 = lambda { |t| t ** 2}

  def self.LambdaFunction1
    @lambda1
  end

  def self.LambdaFunction2
    @lambda2
  end
end

func1 = LambdaFunctions.LambdaFunction1
func2 = LambdaFunctions.LambdaFunction1
func3 = LambdaFunctions.LambdaFunction2

puts func1.equal?(func2) # true
puts func1.equal?(func3) # false
puts func1.equal?(LambdaFunctions.LambdaFunction1) # true
puts func3.equal?(LambdaFunctions.LambdaFunction1) # false
puts func3.equal?(LambdaFunctions.LambdaFunction2) # true

This has been driving me nuts, I'm posting here after a lot of looking around.

I'd like to know if two variables pointing to the same Proc are the pointing to the same Proc.
I'm sure it must be something I'm not getting so for example why do all of these return false?

class LambdaFunctions
  def self.LambdaFunction1
    lambda { |t| t ** 2}
  end
end

a = LambdaFunctions.LambdaFunction1
b = LambdaFunctions.LambdaFunction1

puts LambdaFunctions.LambdaFunction1
puts a
puts b

puts a == b
puts a === b
puts a.eql?(b)
puts a.equal?(b)
puts a == LambdaFunctions.LambdaFunction1
puts a === LambdaFunctions.LambdaFunction1
puts a.eql?(LambdaFunctions.LambdaFunction1)
puts a.equal?(LambdaFunctions.LambdaFunction1)

Thank you Mark, you made it a lot clearer.
In previous it was returning new objects each time so the equal? function was never going to return true. The two lambdas were functionally the same but not the same object.
So if you create one version and then return it back in the method you can test it's identity.
The following makes more sense and works as I intended.

class LambdaFunctions

  @lambda1 = lambda { |t| t ** 2}
  @lambda2 = lambda { |t| t ** 2}

  def self.LambdaFunction1
    @lambda1
  end

  def self.LambdaFunction2
    @lambda2
  end
end

func1 = LambdaFunctions.LambdaFunction1
func2 = LambdaFunctions.LambdaFunction1
func3 = LambdaFunctions.LambdaFunction2

puts func1.equal?(func2) # true
puts func1.equal?(func3) # false
puts func1.equal?(LambdaFunctions.LambdaFunction1) # true
puts func3.equal?(LambdaFunctions.LambdaFunction1) # false
puts func3.equal?(LambdaFunctions.LambdaFunction2) # true

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

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

发布评论

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

评论(2

蓝眼睛不忧郁 2024-09-17 03:02:25

虽然 lambda 实际上是等价的,但每次调用 LambdaFunctions.LambdaFunction1 都会返回 lambda 的一个新实例。对于过程来说,仅通过身份(而不是通过值)进行等效是有意义的,因为实际上不可能确定程序等效性。

我的意思是,如果 procs 可以根据它们所做的事情被确定为等效,那么 lambda { 3 } 和 lambda { 1 + 2 } 将是等效的。对于比这更复杂的 lambda,要确定等效性基本上需要解决停止问题

要确定等效标识(根据评论),请参阅 Object#equal?

== 不同,equal? 方法永远不应该被子类重写:它用于确定对象标识(即 a.equal? (b) 当且仅当ab 是同一对象)。

如果您确实需要 ab 是同一个对象,那么您需要每次都返回相同的 lambda;这意味着您需要将 lambda 分配给 LambdaFunctions 类中的实例变量,然后返回该变量。

ruby-1.9.1-p378 > class LambdaFunctions
ruby-1.9.1-p378 ?>   @func1 = lambda { |t| t ** 2 }
ruby-1.9.1-p378 ?>   def self.LambdaFunction1
ruby-1.9.1-p378 ?>      @func1
ruby-1.9.1-p378 ?>    end
ruby-1.9.1-p378 ?>  end
 => nil 
ruby-1.9.1-p378 > a = LambdaFunctions.LambdaFunction1
 => #<Proc:0x0000010099e370@(irb):10 (lambda)> 
ruby-1.9.1-p378 > b = LambdaFunctions.LambdaFunction1 # same address as a
 => #<Proc:0x0000010099e370@(irb):10 (lambda)> 
ruby-1.9.1-p378 > a == b
 => true 

While the lambda is effectively equivalent, each call to LambdaFunctions.LambdaFunction1 returns a new instance of the lambda. It would make sense for procs to be equivalent only by identity, not by value, since it would be virtually impossible to determine programmatic equivalence.

What I mean is, if procs could be determined to be equivalent based on what they did, then lambda { 3 } and lambda { 1 + 2 } would be equivalent. With lambdas any more complicated than that, to determine equivalence would basically require a solution to the halting problem.

To determine equivalent identity (per the comment), refer to Object#equal?:

Unlike ==, the equal? method should never be overridden by subclasses: it is used to determine object identity (that is, a.equal?(b) iff a is the same object as b).

If you really need a and b to be the same object, then you need to return the same lambda every time; this means you need to assign the lambda to an instance variable in the LambdaFunctions class, for instance, and return that.

ruby-1.9.1-p378 > class LambdaFunctions
ruby-1.9.1-p378 ?>   @func1 = lambda { |t| t ** 2 }
ruby-1.9.1-p378 ?>   def self.LambdaFunction1
ruby-1.9.1-p378 ?>      @func1
ruby-1.9.1-p378 ?>    end
ruby-1.9.1-p378 ?>  end
 => nil 
ruby-1.9.1-p378 > a = LambdaFunctions.LambdaFunction1
 => #<Proc:0x0000010099e370@(irb):10 (lambda)> 
ruby-1.9.1-p378 > b = LambdaFunctions.LambdaFunction1 # same address as a
 => #<Proc:0x0000010099e370@(irb):10 (lambda)> 
ruby-1.9.1-p378 > a == b
 => true 
旧情别恋 2024-09-17 03:02:25

使用 equals 方法进行相等可能不是您想要的,只有当比较的两个对象引用同一对象时,它才会返回 true。我认为在这种情况下 == 可能是您更喜欢的。

我创建了一个 proc_extensions gem 来获取 proc 或 lambda 的源代码。您可以使用它来比较两个 procs 或 lambda 的来源,如下所示:

require 'proc_extensions'

Proc.instance_eval { include ProcExtensions::Source }

class LambdaFunctions

  @lambda1 = lambda { |t| t ** 2}
  @lambda2 = lambda { |t| t ** 2}

  def self.LambdaFunction1
    @lambda1
  end

  def self.LambdaFunction2
    @lambda2
  end
end

func1 = LambdaFunctions.LambdaFunction1.source
func2 = LambdaFunctions.LambdaFunction1.source
func3 = LambdaFunctions.LambdaFunction2.source

func1 == func2 # => true
func1 == func3 # => true
func1 == LambdaFunctions.LambdaFunction1.source # => true
func3 == LambdaFunctions.LambdaFunction1.source # => true
func3 == LambdaFunctions.LambdaFunction2.source # => true

Using the equals method for equality may not be what you intend it will only return true if the two objects being compared refer to the same object. I think == is perhaps what you might prefer in this case.

I created a proc_extensions gem to get the source of a proc or lambda. You could use this to compare the sources of two procs or lambda like this:

require 'proc_extensions'

Proc.instance_eval { include ProcExtensions::Source }

class LambdaFunctions

  @lambda1 = lambda { |t| t ** 2}
  @lambda2 = lambda { |t| t ** 2}

  def self.LambdaFunction1
    @lambda1
  end

  def self.LambdaFunction2
    @lambda2
  end
end

func1 = LambdaFunctions.LambdaFunction1.source
func2 = LambdaFunctions.LambdaFunction1.source
func3 = LambdaFunctions.LambdaFunction2.source

func1 == func2 # => true
func1 == func3 # => true
func1 == LambdaFunctions.LambdaFunction1.source # => true
func3 == LambdaFunctions.LambdaFunction1.source # => true
func3 == LambdaFunctions.LambdaFunction2.source # => true
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文