• Subject: Re: Recursive anonymous functions?
• From: Gabor Grothendieck <ggrothendieck@...>
• Date: Fri, 23 Jul 2004 18:26:54 +0000 (UTC)

Gabor Grothendieck <ggrothendieck <at> myway.com> writes:

:
: Rici Lake <lua <at> ricilake.net> writes:
:
: :
: : On 22-Jul-04, at 9:31 PM, Gabor Grothendieck wrote:
: : >
: : > For example, we can invoke the anonymous factorial function
: : > evaluating it for the argument 3 like this:
: : >
: : >    Recall = function(...)
: : >      return debug.getinfo(2,"f").func(unpack(arg))
: : >    end
: :
: : The use of the debug library is not advisable, unless you are actually
: : debugging. Furthermore, this will not work on the tail-recursive
: : implementation of factorial:
: :
: : print ((function(x, acc)
: :            if x <= 1 then return acc
: :                      else return Recall(x - 1, x * acc)
: :            end
: :          end) (3, 1))
: :
: : stdin:1: attempt to call field `func' (a nil value)
:
: That's too bad; however, one can still do it in a consistent,
: but uglier, way for both examples by using
:
:    debug.getinfo(1,"f").func
:
: inline like this:
:
:    print ((function(x)
:            if x == 0 then return 1
:                      else return x * debug.getinfo(1,"f").func(x - 1)
:            end
:          end) (3, 1))
:
:    print ((function(x, acc)
:            if x <= 1 then return acc
:                      else return debug.getinfo(1,"f").func(x - 1, x * acc)
:            end
:          end) (3, 1))

Here is a slight improvement.  If one defines Recall to return the
function, itself, rather than the function evaluated, then Recall can
still be used in both the non-tail recursion and tail recursion cases
like this:

Recall = function() return debug.getinfo(2,"f").func end

print ((function(x)  -- non-tail recursion example
if x == 0 then return 1
else return x * Recall()(x-1)
end
end) (3))

print((function(x, acc) -- tail recursion example
if x <= 1 then return acc
else
local Recall = Recall()
return Recall(x - 1, x * acc)
end
end)(3,1))

We could have made this entirely symmetric by writing the
non-tail recursion case using the local redefinition of
Recall, as well, like this:

print ((function(x)  -- non-tail recursion version 2
if x == 0 then return 1
else
local Recall = Recall()
return x * Recall(x-1)
end
end) (3))