2010-07-16 63 views
3

這一直在推動着我的堅果,我在這裏張貼了許多四處張望之後。在Ruby中比較兩個lambda/Procs

我想知道兩個指向同一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 

回答

5

雖然拉姆達是有效當量,每次調用LambdaFunctions.LambdaFunction1返回拉姆達的新實例。只有通過身份而不是價值來確定程序對等纔是有意義的,因爲實際上不可能確定程序對等。

我的意思是,如果特效可以根據他們所做的事情確定爲等效,那麼lambda { 3 }lambda { 1 + 2 }將是等效的。隨着lambda比任何更復雜的,確定等效基本上需要解決方案halting problem

爲了確定(每註釋)等效同一性,指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:[email protected](irb):10 (lambda)> 
ruby-1.9.1-p378 > b = LambdaFunctions.LambdaFunction1 # same address as a 
=> #<Proc:[email protected](irb):10 (lambda)> 
ruby-1.9.1-p378 > a == b 
=> true 
+0

我認爲這可能是類似的東西。我想下一個問題是,你如何通過身份測試? – 2010-07-16 22:41:28

+0

我剛剛寫了這個例子,並回過頭來看看你爲我寫了一個例子。非常感謝,現在已經明確指出了這一點。 – 2010-07-16 23:01:13

+0

實際上,在一般情況下,確定程序化等價並不是不可能,它只是*是*不可能的。期。證明:如果編程等價性是可確定的,我可以像這樣解決暫停問題:'def halts?(proc); proc == lambda {while true;結束}結束。 – 2010-07-16 23:02:55

0

使用的相等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