Idea: "Frozen" inner function

David Medlock noone at nowhere.com
Mon Nov 27 11:52:34 PST 2006


Steve Horne wrote:
> On Sun, 26 Nov 2006 15:28:03 +0100, Michael Butscher
> <mbutscher at gmx.de> wrote:
> 
> 
>>Steve Horne wrote:
> 
> 
>>>So for instance, in Python (which does use closures)...
>>>
>>>a = 5
>>>fn = lambda : a
>>>a = 6
>>>print fn()
>>>
>>>The output should be 5, not 6 - the value when the lambda expression
>>>was evaluated.
>>
>>Have you tried that? With Python 2.5 in an interactive session, I get:
>>
>>
>>>>>def test():
>>
>>	a = 5
>>	fn = lambda : a
>>	a = 6
>>	print fn()
>>
>>	
>>
>>>>>test()
>>
>>6
> 
> 
> No, I didn't test, and now I'm a bit embarrassed, and confused.
> 
> I have tonnes of code that uses lambdas, and I'm sure some depends on
> this behaviour. Code which is heavily used and which all seems to
> work. Yet suddenly, I can't get a simple example to work right.
> 
> All I can say is that something's going on in Python that I don't know
> about.
> 
> 
> I've checked my favorite compiler-stuff text (Modern Compiler Design,
> Dick Grune et al) and theres a section (6.3.5.5 Currying a routine)
> that seems to agree with my closure definition more-or-less.
> 
> But this is about currying, not inner functions.
> 
> In the same book, section 6.3.5.3 is directly relevant (title
> "Returning a nested routine as a value"). It describes the
> using-dead-variables issue, but actually suggests keeping the local
> variables for the outer function in a heap frame rather than on the
> stack.
> 
> But...
> 
> 1  This is the variables for the outer function, not the inner
>    function. You put those variables in the stack frame whether
>    the inner function object is actually created or not, and
>    several inner function objects could be created that all refer
>    to the same stack frame.
> 
> 2  It doesn't use the term closure to describe this.
> 
> So basically, I thought I knew what I was talking about, but now I'm
> not so sure.
> 
> Maybe Python is doing the (1) thing, but that leaves me wondering how
> come my existing code is working.
> 
> Incidentally, Amazon seems to have the full text of the book if you
> want to check exactly what it says, but stepping through the pages
> one-by-one to get to the relevant section (around page 490-ish) is
> painful.
> 

In my understanding, closures are like functions which carry state along 
with them.  Like objects but with only a single method: opCall().

in Lua syntax:

function make_adder()
   local sum = 0;
   return function(n) sum = sum + n; return sum; end
end

x = make_adder()
print(x(5))
5
print(x(10))
15

the function returned is a closure of the environment in make_adder.
When the closure carries along the sum value it is called lambda 
lifting. (sum is called an 'upvalue')

Currying simply allows composition of larger functions from smaller 
(incomplete) ones.  In Lua:

function f(a,b) return a + b; end

to curry f with the value of 1:

x = function(b) return f(1 , b); end

or more generally:

def curry(fn,val)
   return function(b) return fn(val,b) end
end

Coroutines are interesting as they also exhibit the same state-capture 
as closures. Here is an equivalent example in Lua:

function adder(sum)
   while(true) do
     sum = sum + coroutine.yield(sum)
   end
end

function make_adder()
   return coroutine.create(adder);
end

a = make_adder()
ok,x = coroutine.resume( a, 5 )
print( x )
ok, x = coroutine.resume( a, 10 )
print( x )


Off the top of my head, so quite probably errors here.
I ran my code in Lua 5.1, though.

-DavidM






More information about the Digitalmars-d mailing list