我可以使用 Ruby 从自身内部引用 lambda 吗?
Posted
技术标签:
【中文标题】我可以使用 Ruby 从自身内部引用 lambda 吗?【英文标题】:Can I reference a lambda from within itself using Ruby? 【发布时间】:2012-03-19 22:31:59 【问题描述】:我希望能够使用 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)
我知道 那 行不通,因为 self
是 main
对象。我做错了吗?我是否在尝试做一些不可能的事情——如果不是,这是因为一些理论上的限制,还是根本没有在 Ruby 中实现?
【问题讨论】:
你熟悉 Y 组合器吗?这可能不是最好的实际解决方案,但从理论的角度来看,它非常有趣。如果您不这样做,请查看this article。小心,它可能会炸毁你的大脑。 【参考方案1】:在以下示例中,lambda 仍然是匿名的,但它有一个引用。 (这是否通过匿名?)
(l = lambda l.call ).call
(感谢 Niklas B. 指出我原始答案中的错误;我只在 IRB 中测试过它,它在那里工作)。
这当然会以SystemStackError: stack level too deep
错误结束,但它说明了目的。
【讨论】:
【参考方案2】:看来匿名函数真的没有任何引用。您可以通过callee查看它
lambda __callee__ .call #=> nil
如果没有引用,您将无法调用此函数。 我只能向你建议一个更干净的变体:
(fac = lambda |n| n==1 ? 1 : n*fac.call(n-1) ).call(5)
【讨论】:
为它创建一个命名函数真的会干净得多。 是的,我的原始版本确实将 lambda 包含在括号中,我在那里运行了 .call() 。不过,这实际上并不是代码简洁的问题,更多的是关于 Ruby 的功能性兔子洞可以走多深。 KL-7 上面有一条评论链接到一篇描述 Y 组合子的文章,这是一篇非常有趣的文章。【参考方案3】:fact = -> (x) x < 2 ? 1 : x*fact.(x-1)
最小函数
【讨论】:
差不多。fact = -> (x) x < 2 ? 1 : x*fact[x-1]
少了一个非空白字符。
@pjs 大多数时候括号比方括号更受欢迎。仅仅因为方括号主要表示对数据的访问(数组、哈希、结构等)。使用括号清楚地表明您正在调用方法/proc/lambda。方括号的用法没有错,但可能会误导不知情的代码阅读者。【参考方案4】:
除了KL-7's comment,这里还有一个Y组合子解决方案:
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
请注意,虽然fac
已被分配,但它并未在 lambda 中使用。
我会使用 Ruby 的 ->
语法和 .()
而不是 .call()
:
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
调用可以通过使用curry
稍微简化:
y = ->(f)
->(x) x.(x) .(
->(x) f.curry.(->(v) x.(x).(v) ) )
fac = y.(
->(f, n) n == 0 ? 1 : n * f.(n - 1)
)
fac.(5) #=> 120
【讨论】:
以上是关于我可以使用 Ruby 从自身内部引用 lambda 吗?的主要内容,如果未能解决你的问题,请参考以下文章