I want to be able to call an anonymous lambda from within itself using Ruby. Consider the following recursive block (returns a factorial). I know I can assign it to a variable, and that variable is within the scope of the lambda:
fac = lambda { |n| n == 1 ? 1 : n * fac.call(n - 1) }
fac.call(5)
But, I want to be able to do the following (for no practical reason as of yet, I'm just interested in exploring the language some more):
(lambda { |n| n == 1 ? 1 : n * self.call(n - 1) }).call(5)
I know that won't work, because self
is the main
object. Am I doing it wrong? Am I trying to do something that's not possible -- and if not, is this because of some theoretical restriction or is it simply not implemented in Ruby?
In Ruby, a lambda is an object similar to a proc. Unlike a proc, a lambda requires a specific number of arguments passed to it, and it return s to its calling method rather than returning immediately.
In Computer Programming, Lambda functions are anonymous functions. Lambda functions in Ruby are no different. Since everything in Ruby is treated as an object, lambdas are also objects in Ruby. Lambdas in Ruby allow us to wrap data and logic in a portable package.
In the following example, the lambda is still anonymous, but it has a reference. (Does that pass for anonymous?)
(l = lambda { l.call }).call
(Thanks to Niklas B. for pointing out the error in my original answer; I had only tested it in IRB and it worked there).
This of course ends in a SystemStackError: stack level too deep
error, but it demonstrates the purpose.
It seems that anonymous function really doesn't have any reference. You can check it by callee
lambda{ __callee__ }.call #=> nil
And without reference you can't call this function. I can propose to you only a little more clean variant:
(fac = lambda{ |n| n==1 ? 1 : n*fac.call(n-1) }).call(5)
fact = -> (x){ x < 2 ? 1 : x*fact.(x-1)}
minimal function
In addition to KL-7's comment, here's a Y combinator solution:
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
You would normally split these:
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
Note that although fac
is being assigned, it is not used within the lambda.
I'd use Ruby's ->
syntax and .()
instead of .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
The y
invocation can be simplified a bit by using 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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With