Chapter 11
A great deal of functional programming amounts to fgx()() kinds of constructs. We
often spell these functions out because there's no real benefit from summarizing the
function into a composite, fgx (). In some cases, however, we might want to use a
composite function with a higher-order function like map(), filter(), or reduce().
We can always resort to the map(f, map(g, x)) method. It might be more clear,
however, to use the map(f_g, x) method to apply a composite to a collection.
It's important to note that there's no inherent performance advantage to either
technique. The map() function is lazy: with two map() functions, one item will be
taken from x, processed by the g() function, and then processed by the f() function.
With a single map() function, an item will be taken from x and then processed by the
f_g() composite function.
In Chapter 14, The PyMonad Library, we'll look at an alternative approach to this
problem of creating composite functions from individual curried functions.
Preprocessing bad data
One cross-cutting concern in some exploratory data analysis applications is how
to handle numeric values that are missing or cannot be parsed. We often have a
mixture of float, int, and Decimal currency values that we'd like to process with
some consistency.
In other contexts, we have not applicable or not available data values that shouldn't
interfere with the main thread of the calculation. It's often handy to allow the Not
Applicable values to pass through an expression without raising an exception.
We'll focus on three bad-data conversion functions: bd_int(), bd_float(), and
bd_decimal(). The composite feature we're adding will be defined before the
built-in conversion function.
Here's a simple bad-data decorator:
import decimal
def bad_data(function):
@wraps(function)
def wrap_bad_data(text, *args, **kw):
try:
return function(text, *args, **kw)
except (ValueError, decimal.InvalidOperation):
cleaned= text.replace(",", "")
return function(cleaned, *args, **kw)
return wrap_bad_data