Functional recipes

Here I'm going to be putting tools and functions that I find myself needing over and over.

To use these functions, you probably want to first import this:

from functools import partial, reduce

Composition

def compose(*fns):
    return reduce(lambda f, g: lambda x: f(g(x)), fns, lambda x: x)

Reversed composition

Like compose, but the functions execute in the opposite direction.

def rcompose(*fns):
    return reduce(lambda f, g: lambda x: f(g(x)), reversed(fns), lambda x: x)

Conjoined execution

Same input, multiple outputs.

def conjoin(*fns):
    return partial(lambda *args, **kw: tuple(fn(*args, **kw) for fn in fns))

Example:

def half(x):
    return x / 2

def double(x):
    return x * 2

half_double = conjoin(half, double)
print(half_double(20))

Remove empty

Remove empty entries.

def remove_empty(items):
    return filter(len, items)

def remove_empty_strings(items):
    return filter(compose(len, str.strip), items)

Negating a function

def negate(fn):
    return partial(lambda *args, **kw: not fn(*args, **kw))

Assign

This takes a collection of dicts and assigns them together to create a new dict. No dicts are edited, only copies are made.

def assign(*dicts):
    return reduce(lambda d1, d2: dict(d1, **d2), dicts, {})

Examples:

assign({'a': 1, 'b': 2}, {'b': 3, 'c': 4})
# -> {'a': 1, 'b': 3, 'c': 4}

assign({'a': 1, 'b': 2}, {'c': 4}, {'dog': 'water'})
# -> {'a': 1, 'b': 2, 'c': 4, 'dog': 'water'}