pythonpython-3.xone-liner

How does this discouraging Python one-liner that displays the mandlebrot set work?


Could you please explain how it works.

In particular: where do a,c,n,s,z come from? And how to convert this to regular functions and their calls?

x=10
y=5
abs( (lambda a: lambda z, c, n: a(a, z, c, n)) (lambda s, z, c, n: z if n == 0 else s(s, z*z+c, c, n-1)) (0, 0.02*x+0.05j*y, 10) )

It was even longer, but I figured out the rest of it.

print('\n'.join([''.join(['*'if abs((lambda a: lambda z, c, n: a(a, z, c, n))(lambda s, z, c, n: z if n == 0 else s(s, z*z+c, c, n-1))(0, 0.02*x+0.05j*y, 40)) < 2 else ' ' for x in range(-80, 20)]) for y in range(-20, 20)]))

This monster expression outputs a pseudo-graphic Mandelbrot fractal to the console.


Solution

  • This function (lambda a: lambda z, c, n: a(a, z, c, n)) can be rewritten as

    def apply_function_to_itself(funk):
        def inner(arg1, arg2, arg3):
            funk(funk, arg1, arg2, arg3)
            
        return inner
    

    This is a functional thing that calls a function with itself as the first argument. This is necessary for recursion in functional languages but in python there is usually a better way.

    This function (lambda s, z, c, n: z if n == 0 else s(s, z*z+c, c, n-1)) can be rewritten as this:

    def transform_n_times(funk, value, c, n):
        if n==0:
            return arg1
        else:
            return funk(funk, value * value + constant, constant, n-1)
    

    We know from the previous function that funk === call_if_n_is_not_0, so this is a recursive function that will apply a operation n times before stopping.

    So basically combined we can rewrite it like this:

    def transform_n_times(value, constant, n):
        for i in range(n):
            value arg1 * arg1 + arg2
        return value
    

    Much simpler.

    Understanding the entire program

    The entire code could be written like this:

    
    def apply_function_to_itself(funk):
        def inner(arg1, arg2, arg3):
            funk(funk, arg1, arg2, arg3)
            
        return inner
    
    def transform_n_times(funk, value, constant, n):
        if n==0:
            return arg1
        else:
            return funk(funk, value * value + constant, constant, n-1)
    
    abs(apply_function_to_itself(call_if_n_is_not_0)(0, 0.02*x+0.05j*y, 10))
    

    Or like this. We can get rid of the apply_function_to_itself entirely but keep the recursion like this:

    def transform_n_times(value, constant, n):
        if n==0:
            return arg1
        else:
            return transform_n_times(funk, value * value + constant, constant, n-1)
    
    abs(transform_n_times(0, 0.02*x+0.05j*y, 10))
    

    Or we can delete the recursion entirely and just use a loop:

    constant = 0.02*x+0.05j*y
    value = 0
    n = 10
    for i in range(n):
        a1 = value * value + constant
    abs(value)
    

    The basic equation behind the mandlebrot set is f(x) = x^2+c which matches this.