我可以使用Ruby从内部引用lambda吗?

时间:2012-03-01 12:16:29

标签: ruby lambda block

我希望能够使用Ruby从内部调用匿名lambda。考虑以下递归块(返回阶乘)。我知道我可以将它分配给变量,并且该变量在lambda的范围内:

fac = lambda { |n| n == 1 ? 1 : n * fac.call(n - 1) }
fac.call(5)

但是,我希望能够做到以下(因为没有任何实际原因,我只是对探索语言感兴趣):

(lambda { |n| n == 1 ? 1 : n * self.call(n - 1) }).call(5)

我知道 不起作用,因为selfmain对象。我做错了吗?我是否尝试做一些不可能的事情 - 如果没有,这是因为某些理论上的限制,还是仅仅没有在Ruby中实现?

4 个答案:

答案 0 :(得分:8)

在下面的示例中,lambda仍然是匿名的,但它有一个引用。 (这会传递匿名吗?)

(l = lambda { l.call }).call

(感谢Niklas B.指出我原来答案中的错误;我只在IRB中进行了测试,并在那里工作过。)

这当然以SystemStackError: stack level too deep错误结束,但它证明了目的。

答案 1 :(得分:5)

似乎匿名函数确实没有任何参考。您可以按callee

进行检查
lambda{ __callee__ }.call #=> nil

如果没有参考,你就无法调用此功能。 我可以向你推荐一个更干净的变种:

(fac = lambda{ |n| n==1 ? 1 : n*fac.call(n-1) }).call(5)

答案 2 :(得分:1)

除了KL-7's comment之外,这里还有一个Y组合解决方案:

/* -cancel returns immediately, but marks a task as being canceled.
 * The task will signal -URLSession:task:didCompleteWithError: with an
 * error value of { NSURLErrorDomain, NSURLErrorCancelled }.  In some 
 * cases, the task may signal other work before it acknowledges the 
 * cancelation.  -cancel may be sent to a task that has been suspended.
 */

您通常会拆分这些:

lambda { |f|
  lambda { |x| x.call(x) }.call(
  lambda { |x| f.call( lambda { |v| x.call(x).call(v) } ) } )
}.call(
  lambda { |f|
    lambda { |n| n == 0 ? 1 : n * f.call(n - 1) }
  }
).call(5) #=> 120

请注意,虽然正在分配y = lambda { |f| lambda { |x| x.call(x) }.call( lambda { |x| f.call( lambda { |v| x.call(x).call(v) } ) } ) } fac = y.call( lambda { |f| lambda { |n| n == 0 ? 1 : n * f.call(n - 1) } } ) fac.call(5) #=> 120 ,但它不会在lambda中使用。

我使用Ruby的fac语法和->代替.()

.call()

使用curry

可以简化y = ->(f) { ->(x) { x.(x) }.( ->(x) { f.(->(v) { x.(x).(v) }) } ) } fac = y.(->(f) { ->(n) { n == 0 ? 1 : n * f.(n - 1) } }) fac.(5) #=> 120 调用
y

答案 3 :(得分:1)

fact = -> (x){ x < 2 ? 1 : x*fact.(x-1)}

最小功能