Monday, March 1, 2021

Some of Python's language constructs, like variable binding, exception handling, sequencing, and iteration, are provided only through language statements. You cannot use statements in an expression context, so it would seem we are up against a limitation. But Python has lambda expressions. Lambda expressions and function calls are all you need to implement variable binding, sequencing and recursion as ordinary Python expressions.

For example, suppose you wish to have a 'let' expression where you bind helper variables 'a' and 'b' to subexpressions. Simply use lambda and immediately call it:

    return (lambda a, b: h(a, b))(f(x), g(y))
Not pretty, but it gets the job done.

If you want to sequence two expressions, write them like this:
    return (lambda ignore: x + 7)(print (x))
The print expression runs first, its result is ignored and then x is added to 7 and returned. Again, this could use a lot of syntactic sugar, but it gets the job done. Alternatively, we could use left to right evaluation of arguments to do our sequencing:
    return (lambda first, second: second)(print(x), x + 7)
In order to implement iteration, we need to bind a name recursively. We'll use the Y operator.
Y = lambda f: (lambda d: d(d)) (lambda x: f (lambda: x (x)))

print (Y (lambda loop:  \
              lambda x: \
                  None if x == 0 else (lambda first, second: second)(
                                           print (x),
                                           loop()(x - 1)))
       (5))

5
4
3
2
1
0
None

Handling exceptions is easy if you use a helper function and some thunks:

def on_error (compute_value, handle_error):
    try:
        return compute_value()
    except:
        return handle_error()


def safe_divide (dividend, divisor):
    return on_error (
           lambda: dividend / divisor,
           lambda: (lambda first, second: second)(
                       print ('divide by zero, answer 1'),
                       1))

print (safe_divide (12, 3))
4
print (safe_divide (12, 0))
divide by zero, answer 1
1

No comments: