Home > database >  Python use lambda as for loop recursion error
Python use lambda as for loop recursion error

Time:12-08

I'm messing with python, and I'm looking for a way to replicate a for loop in a lambda.

Basically, I'd like to convert the function below to a lambda doing the same thing :

def basicForLoop(x):
    for i in range(x):
        print(i)

basicForLoop(100)

For now, I've managed to do it by using recursion and increasing the value to each new recursion :

(lambda f: lambda x: f(f,0, x))(lambda f,current,max: print(current) or f(f, current 1, max) if current <= max else None)(100)

This work rather well, but it hit the max recursion depth as soon as the number start to be too big, so I'm looking for a way to rearrange this lambda so that it can be used without worrying about the recursion depth to make it truly equivalent to the original function.

EDIT : I'm looking for a way to do this while keeping the loop logic directly inside the lambda, delegating the loop to another function like map, join, ... isn't what I'm looking for.

PS. I know very well that this is an abomination that should never be used in reality but I'm just curious about it.

CodePudding user response:

You could do something like that:

x = lambda x: print("\n".join(map(str, list(range(1,x 1)))))

x(100)

Edit:

You can do it like that:

x = lambda x: print(*range(1,x 1), sep='\n')
x(100)

CodePudding user response:

I'm pretty sure this is impossible.

So I'm assuming you want to keep pretty much all of the logic handled by your lambdas, not even using a range. If that's the case, you're not going to get a stack-safe solution in Python. In other languages you could use something called "Tail Recursion", which allows the interpreter/compiler to collapse some recursive calls down to a single stack frame, but Python does not support that.

I don't think you can make this use fewer stack frames, either. Rewriting and re-formatting a bit, and adding explicit names and more print statements:

buildRecursive = (lambda g: 
    print("Running 1st") or
    (lambda x: 
        print ("Running 2nd") or
        g(g,0, x))
)
entry = buildRecursive (lambda f,current,max:
        print("Running 3rd") or
        print(current) or f(f, current 1, max) if current <= max else None)
entry (100)

This should be equivalent to what you have. This has print statements as the first operation of every call, and you can see that you're only running the 3rd one repeatedly. Essentially, you're generating as few stack frames per iteration as possible, given the constraints as I understand them.

As an aside, after some reading I understand why you're doing the or thing, but coming from other languages, that is downright hideous. It might be the python way of doing things, but it's a pretty awful way of sequencing operations - especially because of short-circuiting logic, so if you have try to bind operations such that the first doesn't return None, your code will mysteriously break. I would suggest using a tuple instead - (firstOp, secondOp) - but I think that will have memory or performance implications as Python will actually build the resulting value.

Have you explored languages other than Python? If not I'd say it's time.

  • Related