19

I'm trying to write a lambda-expression that calls itself, but i can't seem to find any syntax for that, or even if it's possible.

Essentially what I wanted to transfer the following function into the following lambda expression: (I realize it's a silly application, it just adds, but I'm exploring what I can do with lambda-expressions in python)

def add(a, b):
   if a <= 0:
      return b
   else:
      return 1 + add(a - 1, b)

add = lambda a, b: [1 + add(a-1, b), b][a <= 0]

but calling the lambda form of add results in a runtime error because the maximum recursion depth is reached. Is it even possible to do this in python? Or am I just making some stupid mistake? Oh, I'm using python3.0, but I don't think that should matter?

Eric Lifka
  • 307
  • 3
  • 9
  • lambda expressions are quite broken in python. i'm not really familiar enough to make a full answer, but if it convinces you, I understand that Guido hates lambda expressions :P – Jeremy Powell Jul 29 '09 at 21:56
  • see here, exact duplicate: http://stackoverflow.com/questions/481692/can-a-lambda-function-call-itself-recursively-in-python – Gordon Gustafson Jul 29 '09 at 22:02
  • 1
    There is nothing broken about them. They are just useless, as you can use a function instead, which is easier to read and understand. – Lennart Regebro Jul 29 '09 at 22:07
  • -1: This is silly. What's wrong with a def? – S.Lott Jul 30 '09 at 00:49
  • 9
    He was pretty clear: learning how lambdas work. If you're going to -1 questions from people just trying to learn, you've got a lot of downvoting to do. Learning and experimenting sure is evil! – Glenn Maynard Jul 30 '09 at 02:22
  • @Glenn Maynard: "i can't seem to find any syntax for that" is all the hint someone needs that it's not supported or even sensible. This isn't an "experiment" it's "I want to do this in spite of obvious language rules preventing it." – S.Lott Jul 30 '09 at 12:15
  • 5
    @S.Lott: this isn't silly at all, and it's the foundation of how recursive algorithms are expressed in theoretical computer science. Now, there's a big difference between practical software engineering and theoretical computer science, but that doesn't mean that one is "sensible" and the other is "silly". – Daniel Pryden Aug 02 '09 at 21:32
  • This question and all its answers are hilarious. – A B Aug 02 '09 at 22:06
  • These concepts are important and sometimes quite practical. Even fixed-point combinator functions have applications, for example with trampolining. If you have tail-recursive functions designed to work with the Z combinator, a trampolining substitute can eliminate excessive stack frames without implementation changes. – wberry May 26 '13 at 18:51

6 Answers6

20

Maybe you need a Y combinator?

Edit - make that a Z combinator (I hadn't realized that Y combinators are more for call-by-name)

Using the definition of the Z combinator from Wikipedia

>>> Z = lambda f: (lambda x: f(lambda *args: x(x)(*args)))(lambda x: f(lambda *args: x(x)(*args)))

Using this, you can then define add as a completely anonymous function (ie. no reference to its name in its definition)

>>> add = Z(lambda f: lambda a, b: b if a <= 0 else 1 + f(a - 1, b))
>>> add(1, 1)
2
>>> add(1, 5)
6
Ben Lings
  • 27,150
  • 13
  • 69
  • 79
9

Perhaps you should try the Z combinator, where this example is from:

>>> Z = lambda f: (lambda x: f(lambda *args: x(x)(*args)))(lambda x: f(lambda *args: x(x)(*args)))
>>> fact = lambda f: lambda x: 1 if x == 0 else x * f(x-1)
>>> Z(fact)(5)
120
Barry Kelly
  • 39,856
  • 4
  • 99
  • 180
6

First of all recursive lambda expressions are completely unnecessary. As you yourself point out, for the lambda expression to call itself, it needs to have a name. But lambda expressions is nothing else than anonymous functions. So if you give the lambda expression a name, it's no longer a lambda expression, but a function.

Hence, using a lambda expression is useless, and will only confuse people. So create it with a def instead.

But yes, as you yourself discovered, lambda expressions can be recursive. Your own example is. It's in fact so fantastically recursive that you exceed the maximum recursion depth. So it's recursive alright. Your problem is that you always call add in the expression, so the recursion never stops. Don't do that. Your expression can be expressed like this instead:

add = lambda a, b: a > 0 and (1 + add(a-1, b)) or b

Which takes care of that problem. However, your first def is the correct way of doing it.

Lennart Regebro
  • 147,792
  • 40
  • 207
  • 241
  • 10
    Having or not having a name has absolutely nothing to do with whether something is a lambda. A lambda is a logical *expression* (which happens to have the same interface as a function). It's perfectly ordinary to give them a name. – Glenn Maynard Jul 29 '09 at 22:15
  • 1
    In Python, lambda expression are implemented as anonymous functions. Hence, everything I stated above is correct. What lambdas are in theoretical mathematics is not relevant for this question. Of course it's "ordinary" to give them a name. The point is that in Python you could then just have used a normal function, ans saved yourself the trouble. – Lennart Regebro Jul 29 '09 at 22:53
  • Ah right, so what I did was the "some stupid mistake" option. I didn't even pause to think that the list would get fully evaluated first. Thanks for the face palm :) – Eric Lifka Jul 29 '09 at 23:22
  • 4
    I have no interest in theoretical math. You said that a lambda is an anonymous function, and giving a lambda a name makes it not a lambda. You're incorrect. Being anonymous or having a name has exactly nothing to do with whether a Python lambda is a lambda. – Glenn Maynard Jul 29 '09 at 23:22
  • No, I said "lambda expressions are anonymous functions", and in the context of Python (which this is) this is exactly what they are. So if you give it a name, it is, for all intents and purposes, just a normal function. There is no practical or theroretical difference. – Lennart Regebro Jul 30 '09 at 00:45
  • 4
    "if you give the lambda expression a name, it's no longer a lambda expression". It's right there, and it's wrong. I'm finished discussing this. – Glenn Maynard Jul 30 '09 at 04:03
  • If a lambda is an anonymous function (and it is), what is then a non-anonymous lambda? Right, a function. Again, there is no practical difference between a function and a named lambda. This is a fact. – Lennart Regebro Jul 30 '09 at 06:15
3
add = lambda a, b: b if a <= 0 else 1 + add(a - 1, b)
Glenn Maynard
  • 50,887
  • 9
  • 110
  • 128
1

You want the Y combinator, or some other fixed point combinator.

Here's an example implementation as a Python lambda expression:

Y = lambda g: (lambda f: g(lambda arg: f(f)(arg))) (lambda f: g(lambda arg: f(f)(arg)))

Use it like so:

factorial = Y(lambda f: (lambda num: num and num * f(num - 1) or 1))

That is, you pass into Y() a single-argument function (or lambda), which receives as its argument a recursive version of itself. So the function doesn't need to know its own name, since it gets a reference to itself instead.

Note that this does get tricky for your add() function because the Y combinator only supports passing a single argument. You can get more arguments by currying -- but I'll leave that as an exercise for the reader. :-)

Daniel Pryden
  • 54,536
  • 12
  • 88
  • 131
  • Or just use Z combinator above which supports any number of positional arguments. You can also support keyword arguments in the same way if desired. – wberry May 26 '13 at 19:07
0

a little late ... but I just found this gem @ http://metapython.blogspot.com/2010/11/recursive-lambda-functions.html

def myself (*args, **kw):
    caller_frame = currentframe(1)
    code = caller_frame.f_code
    return  FunctionType(code, caller_frame.f_globals)(*args,**kw)

print "5! = "
print (lambda x:1 if n <= 1 else myself(n-1)*n)(5)
Joran Beasley
  • 93,863
  • 11
  • 131
  • 160