Ruby:将 proc 转换为 lambda?
是否可以将 proc 风格的 Proc 转换为 lambda 风格的 Proc?
有点惊讶的是,这不起作用,至少在 1.9.2 中:
my_proc = proc {|x| x}
my_lambda = lambda &p
my_lambda.lambda? # => false!
Is it possible to convert a proc-flavored Proc into a lambda-flavored Proc?
Bit surprised that this doesn't work, at least in 1.9.2:
my_proc = proc {|x| x}
my_lambda = lambda &p
my_lambda.lambda? # => false!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
追踪这个有点棘手。查看
Proc#lambda?
对于 1.9,有一个关于 proc 和 lamdba 之间差异的相当长的讨论。归根结底,
lambda
强制执行正确的参数数量,而proc
则不然。从该文档中,将 proc 转换为 lambda 的唯一方法如以下示例所示:如果你想避免污染任何类,你可以在匿名对象上定义一个单例方法,以便将
proc
强制转换为lambda
:This one was a bit tricky to track down. Looking at the docs for
Proc#lambda?
for 1.9, there's a fairly lengthy discussion about the difference betweenproc
s andlamdba
s.What it comes down to is that a
lambda
enforces the correct number of arguments, and aproc
doesn't. And from that documentation, about the only way to convert a proc into a lambda is shown in this example:If you want to avoid polluting any class, you can just define a singleton method on an anonymous object in order to coerce a
proc
to alambda
:不可能毫无困难地将 proc 转换为 lambda。 Mark Rushakoff 的答案不会保留块中
self
的值,因为self
会变成Object.new
。 Pawel Tomulik 的答案无法与 Ruby 2.1 一起使用,因为define_singleton_method
现在返回一个 Symbol,因此to_lambda2
返回:_.to_proc
。我的答案是也是错误的:
它在块中保留了
self
的值:但它因
instance_exec
而失败:我必须使用
block .binding.eval('self')
找到正确的对象。我将我的方法放在匿名模块中,因此它永远不会污染任何类。然后我将我的方法绑定到正确的对象。尽管该对象从未包含该模块,但这仍然有效!绑定方法生成一个 lambda。66.instance_exec &q
失败,因为q
是秘密绑定到42
的方法,而instance_exec
不能重新绑定该方法。人们可以通过扩展q
来公开未绑定的方法,并重新定义instance_exec
以将未绑定的方法绑定到不同的对象来解决此问题。即便如此,module_exec
和class_exec
仍然会失败。问题是
Hash.class_exec &$q
定义了Array#greet
而不是Hash#greet
。 (虽然$q
是一个匿名模块的秘密方法,但它仍然在Array
中定义方法,而不是在匿名模块中。)使用原始 proc,Hash .class_exec &$p
将定义Hash#greet
。我的结论是convert_to_lambda
是错误的,因为它不能与class_exec
一起使用。It is not possible to convert a proc to a lambda without trouble. The answer by Mark Rushakoff doesn't preserve the value of
self
in the block, becauseself
becomesObject.new
. The answer by Pawel Tomulik can't work with Ruby 2.1, becausedefine_singleton_method
now returns a Symbol, soto_lambda2
returns:_.to_proc
.My answer is also wrong:
It preserves the value of
self
in the block:But it fails with
instance_exec
:I must use
block.binding.eval('self')
to find the correct object. I put my method in an anonymous module, so it never pollutes any class. Then I bind my method to the correct object. This works though the object never included the module! The bound method makes a lambda.66.instance_exec &q
fails becauseq
is secretly a method bound to42
, andinstance_exec
can't rebind the method. One might fix this by extendingq
to expose the unbound method, and redefininginstance_exec
to bind the unbound method to a different object. Even so,module_exec
andclass_exec
would still fail.The problem is that
Hash.class_exec &$q
definesArray#greet
and notHash#greet
. (Though$q
is secretly a method of an anonymous module, it still defines methods inArray
, not in the anonymous module.) With the original proc,Hash.class_exec &$p
would defineHash#greet
. I conclude thatconvert_to_lambda
is wrong because it doesn't work withclass_exec
.这是可能的解决方案:
应该在 Ruby 2.1+ 上工作
Here is possible solution:
Should work on Ruby 2.1+
用于将 procs 转换为 lambda 的跨 ruby 兼容库:
https://github.com/schneems/proc_to_lambda
宝石:
http://rubygems.org/gems/proc_to_lambda
Cross ruby compatiable library for converting procs to lambdas:
https://github.com/schneems/proc_to_lambda
The Gem:
http://rubygems.org/gems/proc_to_lambda
上面的代码不能很好地与
instance_exec
配合使用,但我认为有一个简单的修复方法。这里我有一个例子来说明问题和解决方案:to_lambda1
基本上是Mark提出的实现,to_lambda2
是“固定”代码。上面脚本的输出是:
事实上,我希望
instance_exec
输出A
,而不是Object
(instance_exec
应该改变绑定)。我不知道为什么它的工作方式不同,但我认为define_singleton_method
返回一个尚未绑定到Object
和Object#method
的方法返回一个已经绑定的方法。The above code doesn't play nicely with
instance_exec
but I think there is simple fix for that. Here I have an example which illustrates the issue and solution:to_lambda1
is basically the implementation proposed by Mark,to_lambda2
is a "fixed" code.The output from above script is:
In fact I'd expect
instance_exec
to outputA
, notObject
(instance_exec
should change binding). I don't know why this work differently, but I suppose thatdefine_singleton_method
returns a method that is not yet bound toObject
andObject#method
returns an already bound method.