Hacking together a multi-statement lambda isn't quite as bad as pyrospade makes out: sure we *could* compose a bunch of monadic functions using bind, like in Haskell, but since we're in the impure world of Python, we might as well use side-effects to achieve the same thing.

I cover a few ways to do this on [my blog](http://chriswarbo.net/blog/2012-11-17-anonymous_closures_in_python.html).

For example, Python guarantees to evaluate the elements of a tuple in order, so we can use `,` much like an imperative `;`. We can replace many statements, like `print`, with expressions, like `sys.stdout.write`.

Hence the following are equivalent:

 def print_in_tag_def(tag, text):
 print "<" + tag + ">"
 print text
 print "</" + tag + ">"

 import sys
 print_ = sys.stdout.write
 print_in_tag_lambda = lambda tag, text: (print_("<" + tag + ">"),
 print_(text),
 print_("</" + tag + ">"),
 None)[-1]

Note that I've added a `None` at the end, and extracted it using `[-1]`; this sets the return value explicitly. We don't have to do this, but without it we'd get a funky `(None, None, None)` return value, which we may or may not care about.

So we can sequence IO actions. What about local variables?

Python's `=` forms an statement, so we need to find an equivalent expression. One way is to mutate the contents of datastructure, passed in as an argument. For example:

 def stateful_def():
 foo = 10
 bar = foo * foo
 foo = 2
 return foo + bar

 stateful_lambda = (lambda state: lambda *_: (state.setdefault('foo', 10),
 state.setdefault('bar', state.get('foo') * state.get('foo')),
 state.pop('foo'),
 state.setdefault('foo', 2),
 state.get('foo') + state.get('bar'))[-1])({})

There are few tricks being used in `stateful_lambda`:

 - The `*_` argument allows our lambda to take *any* number of arguments. Since this allows *zero* arguments, we recover the calling convention of `stateful_def`.
 - Calling an argument `_` is just a convention which says "I'm not going to use this variable"
 - We have one ("wrapper") function returning another ("main") function: `lambda state: lambda *_: ...`
 - Thanks to [lexical scope](http://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scoping), the argument of the first function will be in-scope for the second function
 - Accepting some arguments now and returning another function to accept the rest later is known as [currying](http://en.wikipedia.org/wiki/Currying)
 - We immediately call the "wrapper" function, passing it an empty dictionary: `(lambda state: ...)({})`
 - This lets us assign a variable `state` to a value `{}` without using an assignment statement (eg. `state = {}`)
 - We treat keys and values in `state` as variable names and bound values
 - This is less cumbersome than using immediately-called lambdas
 - This allows us to mutate the values of variables
 - We use `state.setdefault(a, b)` instead of `a = b` and `state.get(a)` instead of `a`
 - We use a tuple to chain together our side-effects, like before
 - We use `[-1]` to extract the last value, which acts like a `return` statement 

Of course this is pretty cumbersome, but we can make a nicer API with helper functions:

 # Keeps arguments and values close together for immediately-called functions
 callWith = lambda x, f: f(x)

 # Returns the `get` and `setdefault` methods of a new dictionary
 mkEnv = lambda *_: callWith({},
 lambda d: (d.get,
 lambda k, v: (d.pop(k), d.setdefault(k, v))))

 # A helper for providing a function with a fresh `get` and `setdefault`
 inEnv = lambda f: callWith(mkEnv(), f)

 # Delays the execution of a function
 delay = lambda f x: lambda *_: f(x)

 # Uses `get` and `set`(default) to mutate values
 stateful_lambda = delay(inEnv, lambda get, set: (set('foo', 10),
 set('bar', get('foo') * get('foo')),
 set('foo', 2),
 get('foo') + get('bar'))[-1])