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

我可以使用Ruby从lambda内部引用它吗?,ruby,lambda,block,Ruby,Lambda,Block,我希望能够使用Ruby从内部调用匿名lambda。考虑下面的递归块(返回阶乘)。我知道我可以将其分配给一个变量,该变量在lambda的范围内: fac = lambda { |n| n == 1 ? 1 : n * fac.call(n - 1) } fac.call(5) 但是,我希望能够做到以下几点(目前还没有实际原因,我只是对进一步探索该语言感兴趣): 我知道这是行不通的,因为self是main对象。我做错了吗?我是在尝试做一些不可能的事情吗?如果不是的话,这是因为一些理论上的限制,还是

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

fac = lambda { |n| n == 1 ? 1 : n * fac.call(n - 1) }
fac.call(5)
但是,我希望能够做到以下几点(目前还没有实际原因,我只是对进一步探索该语言感兴趣):


我知道这是行不通的,因为
self
main
对象。我做错了吗?我是在尝试做一些不可能的事情吗?如果不是的话,这是因为一些理论上的限制,还是根本没有在Ruby中实现?

看来匿名函数实际上没有任何引用。你可以通过电话查一下

没有引用就不能调用这个函数。 我只能向你建议一个更干净的变体:

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

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

(感谢Niklas B.指出了我原始答案中的错误;我只在IRB中测试了它,它在那里工作)

当然,这会导致一个
SystemStackError:stack level-too-deep
错误,但它说明了目的。

此外,这里还有一个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
调用可以通过以下方式稍微简化:

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

最小函数

您熟悉Y combinator吗?这可能不是最好的实际解决方案,但从理论角度来看,它非常有趣。如果没有,请看一看。小心,它可能会让你的大脑崩溃。只为它创建一个命名函数会更干净。是的,我的原始版本确实将lambda括在括号中,我在那里运行了一个.call()。不过,这并不是一个真正的代码简洁性问题,更多的是关于Ruby的功能兔子洞到底有多深。KL-7上面有一条评论,链接到一篇描述Y组合子的文章,这是一篇非常有趣的文章
fact=->(x){x<2?1:x*fact[x-1]}
少了一个非空白字符。@pjs大多数时间括号优于方括号。因为方括号主要表示对数据的访问(数组、散列、结构等)。使用括号清楚地表明您正在调用一个方法/proc/lambda。方括号的用法没有错,但可能会误导不知情的代码读取器。
(l = lambda { l.call }).call
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
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 = ->(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
fact = -> (x){ x < 2 ? 1 : x*fact.(x-1)}