2014-07-16 32 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