比较Ruby中的两个Lambda/Proc函数

3

这让我很困扰,经过大量搜索后,我在这里发布了帖子。

我想知道两个指向同一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)

感谢Mark,你让它变得更清晰了。 之前返回的是新对象,所以equal?函数永远不会返回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
2个回答

6
虽然lambda函数在实际上是等效的,但每次调用LambdaFunctions.LambdaFunction1都会返回一个新的lambda实例。如果procs只能根据标识而不是值来确定等价性,那么这将是有意义的,因为基本上不可能确定编程等价性。我的意思是,如果procs可以根据它们所做的事情确定它们是等价的,那么lambda { 3 }和lambda { 1 + 2 }将是等价的。对于比这更复杂的lambda函数,要确定等价性基本上需要解决停机问题。要确定等价标识(根据注释),请参阅Object#equal?:与==不同,equal?方法不应被子类覆盖:它用于确定对象标识(即,当且仅当a是与b相同的对象时,a.equal?(b))。
如果您确实需要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 

我想可能就是那样。那么我接下来的问题是,你是如何通过身份测试的呢? - Craig Norton
我刚刚写了一个例子,回来看到你为我写了一个例子。非常感谢,现在指出来后很明显了。 - Craig Norton
实际上,在一般情况下,确定编程等价性不仅是几乎不可能的,而是根本不可能。证明:如果可以判断编程等价性,我就可以像这样解决停机问题:def halts?(proc); proc == lambda { while true; end } end - Jörg W Mittag

0

使用equals方法来判断相等性可能不是你想要的,它只会在两个被比较的对象引用同一个对象时返回true。我认为在这种情况下,你可能更喜欢使用==

我创建了一个proc_extensions gem来获取proc或lambda的源代码。你可以使用它来比较两个proc或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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接