This isn’t a question – it’s just a comment that I find it awesome and
only slightly mysterious that a lambda can reference the variable it is
assigned to in its body, such as p here:
p = lambda {|n| puts “bing #{n}” ; p.call(n-1) if n > 0 }
p.call(5)
bing 5
bing 4
bing 3
bing 2
bing 1
bing 0
=> nil
I guess that’s the power of a real lexical closure. Very handy.
Fearless F. wrote in post #988575:
This isn’t a question – it’s just a comment that I find it awesome and
only slightly mysterious that a lambda can reference the variable it is
assigned to in its body, such as p here:
p = lambda {|n| puts “bing #{n}” ; p.call(n-1) if n > 0 }
p.call(5)
bing 5
bing 4
bing 3
bing 2
bing 1
bing 0
=> nil
I guess that’s the power of a real lexical closure. Very handy.
For a real eye-opener, see this discussion from 2007.
https://groups.google.com/d/topic/comp.lang.ruby/OlHsBJoud_0/discussion
Fearless F. wrote in post #988575:
This isn’t a question – it’s just a comment that I find it awesome and
only slightly mysterious that a lambda can reference the variable it is
assigned to in its body,
How do recursive methods grab you?
def factorial(n)
if n == 1
1
else
n * factorial(n-1)
end
end
puts factorial(3)
–output:–
6
You might want to ponder the difference between your example and a
recursive method.
7stud – wrote in post #988636:
How do recursive methods grab you?
…
You might want to ponder the difference between your example and a
recursive method.
@7stud: Pardon if I wasn’t clear in my OP, but I was asking about
recursion. [For the record, Lisp was one of my first programming
languages, and I often find it easier to think in terms of recursion
than in iteration. I’d be more impressed if you wrote your factorial
routine as a lazy-eval’d stream, ala Abelson & Sussman SICP. ;)]
What I was surprised about was the scoping of variables in assignment
statements. I guess it makes sense. Assume that p is previously
undefined, then a reference on the RHS to p like this:
p = p + 1
will raise an error. But wrapped inside a lambda, the reference to p is
deferred, so it all works:
p = lambda { |n| p.call(n-1) if (n > 0) }
As I said, that’s the power of a lexical closure.
Content preview: On 22.03.2011 01:47, Albert S. wrote: > Ruby U.
wrote
in post #988632: >> For a real eye-opener, see this discussion from
2007.
>>
https://groups.google.com/d/topic/comp.lang.ruby/OlHsBJoud_0/discussion
> > Thanks. Here’s an alternative link, for those who have trouble
with the
> above: […]
Content analysis details: (-2.9 points, 5.0 required)
pts rule name description
-1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP
-1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1%
[score: 0.0000]
X-Cloudmark-Analysis: v=1.1
cv=vUpxTctd+kpWCBtSXXIkt5ll4Z8E5Qu9nLREXC/hfIo= c=1 sm=0
a=aofHTkXiRO8A:10 a=ecd9y14Xgu0A:10 a=IkcTkHD0fZMA:10 a=1XWaLZrsAAAA:8
a=s5ue6VMcvd2SwaUa7CYA:9 a=MuuHW-lmGfA3qC-griTi7eTKR3oA:4
a=QEXdDO2ut3YA:10 a=HpAAvcLHHh0Zw7uRqdWCyQ==:117
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
Precedence: bulk
Lines: 12
List-Id: ruby-talk.ruby-lang.org
List-Software: fml [fml 4.0.3 release (20011202/4.0.3)]
List-Post: mailto:[email protected]
List-Owner: mailto:[email protected]
List-Help: mailto:[email protected]?body=help
List-Unsubscribe: mailto:[email protected]?body=unsubscribe
Received-SPF: none (Address does not pass the Sender Policy Framework)
SPF=FROM;
[email protected];
remoteip=::ffff:221.186.184.68;
remotehost=carbon.ruby-lang.org;
helo=carbon.ruby-lang.org;
receiver=eq4.andreas-s.net;
On 22.03.2011 01:47, Albert S. wrote:
Ruby U. wrote in post #988632:
For a real eye-opener, see this discussion from 2007.
https://groups.google.com/d/topic/comp.lang.ruby/OlHsBJoud_0/discussion
Thanks. Here’s an alternative link, for those who have trouble with the
above:
Thanks that you mention it, I was able to see that groups was loading
the page but then replaced it’s content shortly afterwards.
Ruby U. wrote in post #988632:
For a real eye-opener, see this discussion from 2007.
https://groups.google.com/d/topic/comp.lang.ruby/OlHsBJoud_0/discussion
Thanks. Here’s an alternative link, for those who have trouble with the
above:
http://www.ruby-forum.com/topic/131109
Fearless F. wrote in post #988777:
7stud – wrote in post #988636:
How do recursive methods grab you?
…
You might want to ponder the difference between your example and a
recursive method.
@7stud: Pardon if I wasn’t clear in my OP, but I was asking about
recursion.
My point was that a recursive method seems harder to explain than your
lambda example. As you detailed, your lambda example can be explained
by a closure.
In the case of a recursive method, how do you explain being able to call
a name that doesn’t even exist yet? Is it because what’s really
happening is something like this:
factorial = Method.new(Object) do
if n == 1
1
else
n * factorial(n-1)
end
end
…and therefore a closure can explain why it works? In ruby, you can
certainly do something this:
MyClass = Class.new do
def greet
puts ‘hi’
end
end
MyClass.new.greet
–output:–
hi
7stud – wrote in post #988797:
@7stud: Pardon if I wasn’t clear in my OP, but I was asking about
recursion.
My point was that a recursive method seems harder to explain than your
lambda example. As you detailed, your lambda example can be explained
by a closure.
Yeah, well, I apologize, but that was my typo. I meant “I wasn’t
asking about recursion”. (And no, recursion doesn’t seem particularly
difficult to explain, does it?!?
Fearless F. wrote in post #988777:
What I was surprised about was the scoping of variables in assignment
statements. I guess it makes sense. Assume that p is previously
undefined, then a reference on the RHS to p like this:
p = p + 1
will raise an error. But wrapped inside a lambda, the reference to p is
deferred, so it all works:
p = lambda { |n| p.call(n-1) if (n > 0) }
As I said, that’s the power of a lexical closure.
“The scoping of variables in assignment” is exactly the same in both
cases.
p = p + 1 does not fail because p is undefined. p is defined. Its
value is nil. The error results from NilClass#+ not existing. This has
nothing to do with “the power of the lexical closure”.
Local variables are discovered at compile time. p gets defined at the
beginning of the scope, before the line “p = p + 1”, and it’s
assigned the value of nil. Try
p = p.to_i + 1
and observe the non-error. Even better, try
def foo
puts local_variables #=>bar
bar = 99
end
The reference to p inside the lambda is not deferred. At compile-time,
the p inside the lambda is bound to the local variable p, just as the
p on the right-hand side of “p = p + 1” is bound to the local variable
p. There is nothing special going on as a result of the lambda being
present.