Search code examples
pythonpython-2.7lambda

Python lambda function to calculate factorial of a number


I have just started learning python. I came across lambda functions. On one of the problems, the author asked to write a one liner lambda function for factorial of a number.

This is the solution that was given:

num = 5
print (lambda b: (lambda a, b: a(a, b))(lambda a, b: b*a(a, b-1) if b > 0 else 1,b))(num)

I cannot understand the weird syntax. What does a(a,b) mean?

Can someone explain?

Thanks


Solution

  • The factorial itself is almost as you'd expect it. You infer that the a is... the factorial function. b is the actual parameter.

    <factorial> = lambda a, b: b*a(a, b-1) if b > 0 else 1
    

    This bit is the application of the factorial:

    <factorial-application> = (lambda a, b: a(a, b))(<factorial>, b)
    

    a is the factorial function itself. It takes itself as its first argument, and the evaluation point as the second. This can be generalized to recursive_lambda as long as you don't mind a(a, b - 1) instead of a(b - 1):

    recursive_lambda = (lambda func: lambda *args: func(func, *args))
    print(recursive_lambda(lambda self, x: x * self(self, x - 1) if x > 0 else 1)(6))
    # Or, using the function verbatim:
    print(recursive_lambda(lambda a, b: b*a(a, b-1) if b > 0 else 1)(6))
    

    So we have the outer part:

    (lambda b: <factorial-application>)(num)
    

    As you see all the caller has to pass is the evaluation point.


    If you actually wanted to have a recursive lambda, you could just name the lambda:

    fact = lambda x: 1 if x == 0 else x * fact(x-1)
    

    If not, you can use a simple helper function. You'll notice that ret is a lambda that can refer to itself, unlike in the previous code where no lambda could refer to itself.

    def recursive_lambda(func):
        def ret(*args):
            return func(ret, *args)
        return ret
    
    print(recursive_lambda(lambda factorial, x: x * factorial(x - 1) if x > 1 else 1)(6))  # 720
    

    Both ways you don't have to resort to ridiculous means of passing the lambda to itself.