2014-07-16 33 views
0

我想在一個lambda中使用一個變量,並使結果Proc保留該值,就像它是一個常數一樣。固定值lambda

如果我做了以下

x = 5 
f = lambda {x} 
x = 4 
f.call 

我得到4.如何構建一個lambda(或PROC對象,或類似的東西),所以它總是返回什麼x在其施工時,無論x的價值在當時的價值?

我有一個(可能很大)的一組動態生成的類,我希望每個人對於某個常量(連接客戶端的主機名,FWIW)都有不同的值。由於我無法控制的原因,我不得不堅持使用多種子體系結構 - 我無法修改代碼,以便各種主機名作爲參數傳遞給構造函數。

+0

你真的需要它是一個lambda? – Kroltan

+0

我需要能夠在代碼中使用猴子補丁:'myclass.class_eval {define_method :: new_method,maybe_lambda_expression}' –

+2

@AndrewCone你能解釋一下你實際上想要做什麼嗎?真的,非假設的,未經編輯的條款? –

回答

2

這裏是你會如何做一個函數內的主機名標記:

def tag_hostname(obj, hostname) 
    obj.singleton_class.class_exec(hostname) do |hostname| 
    define_method :hostname, -> { hostname } 
    end 
end 

用法示例:

Foo = Class.new 
Bar = Class.new 
tag_hostname Foo, 'foo.example.com' 
tag_hostname Bar, 'bar.example.com' 
Foo.hostname # => 'foo.example.com' 
Bar.hostname # => 'bar.example.com' 

或者,也許你想與Foo::HOSTNAME,而不是工作?然後它更容易,只需使用Module#const_set即可。


要回答原來的問題,你可以將x綁定到功能範圍。像這樣:

def constantly(x) 
    ->(*) { x } 
end 

用法示例:

> a = constantly(42) 
> a.call 
=> 42 
> a.call(1, 2, 3) 
=> 42 

(順便說一句,這個名字constantly是Common Lisp的)

+0

不錯,有沒有辦法做到這一點,沒有「def」?如果可能的話,我想將它作爲單個函數中的代碼來完成。 –

+0

@AndrewCone如果您只能使用lambda表達式,請參閱我的答案。 – Kroltan

+0

謝謝。在我的情況下,Lambdas更可取,但這個答案的解決方案也很有啓發性。 –

1

我不知道如何與只有一個調用來完成這個和拉姆達,但有可能與兩個呼叫並仍然是單個的λ:

x = 1 
f = lambda { 
    #first call binds value of x to internal variable of lambda 
    @x = x if @x.nil? 
    return @x 
} 
puts f.call #binds x to lambda return 
x = 2 

puts f.call #returns the original x 

如果您的實際拉mbda比簡單地返回x更復雜,你可能想把實際的代碼包裝在if [email protected]?中,所以它不會被第一次調用。

我會推薦Chris Hester-Young的回答,除非你只能因任何原因使用lambdas。

+0

對不起,但你錯了。您在lambda *中定義的@ x不是它的內部變量,而是由'self'引用的當前對象的實例變量。試着在第一個'f.call'之後打印或覆蓋'@ x'來檢查你自己。 –

0

我必須問爲什麼你想要一個lambda在這裏。 lambda被設計用來在代碼被調用時評估它。所以,如果你設置一個lambda來評估x,那麼這意味着當你調用lambda時你需要x的值。所以如果你在調用f之前改變了x,那麼就其本質而言,lambda會完全做你不想做的事情。儘管如此,我的第一個傾向是使用#dup,但#dup不適用於立即數(請參閱this)。不知道您是否真的在這裏使用數字,或者您是否將此用作簡單示例。儘管在使用字符串完成此操作之後,#dup仍然不起作用,因爲直到字符串引用發生更改後纔會重複該字符串。

這使我想到了第3點。這裏發生的一部分是,當你在Ruby中設置一個變量(以及大多數編程語言)時,它會在內存中創建對該變量地址的引用,而不是該變量的值。所以當你說f = lambda {x}時,真正意義的是「當我打電話給f.call時,我希望它到達x存儲在內存中的位置,並返回所有內容。」

希望這會有所幫助。

+0

編輯了這個問題,以包含我需要的不是lambda的可能性 –

1

lambda中的變量發生變化,因爲它與定義和賦值處於相同的範圍。 您需要附上它作爲closure內的高價值。

要使用您的示例代碼可能看起來像:

x = 5 
f = proc {|arg=x| lambda {arg}}.call 
# created outer scope with proc and `catched' x value in arg 
# inner lambda as a closure as a result of #call is assigned to f 
x = 4 
p f.call # 5