Chapter 2
The topics are as follows:
- Referential transparency: When looking at lazy evaluation and the various
kinds of optimization that are possible in a compiled language, the idea
of multiple routes to the same object is important. In Python, this isn't as
important because there aren't any relevant compile-time optimizations. - Currying: The type systems will employ currying to reduce multiple-argument
functions to single-argument functions. We'll look at currying in some depth in
Chapter 11, Decorator Design Techniques. - Monads: These are purely functional constructs that allow us to structure a
sequential pipeline of processing in a flexible way. In some cases, we'll resort
to imperative Python to achieve the same end. We'll also leverage the elegant
PyMonad library for this. We'll defer this to Chapter 14, The PyMonad Library.
Summary
In this chapter, we've identified a number of features that characterize the functional
programming paradigm. We started with first-class and higher-order functions.
The idea is that a function can be an argument to a function or the result of a
function. When functions become the object of additional programming,
we can write some extremely flexible and generic algorithms.
The idea of immutable data is sometimes odd in an imperative and object-oriented
programming language such as Python. When we start to focus on functional
programming, however, we see a number of ways that state changes can be
confusing or unhelpful. Using immutable objects can be a helpful simplification.
Python focuses on strict evaluation: all sub-expressions are evaluated from
left-to-right through the statement. Python, however, does perform some
non-strict evaluation. The or, and, and if-else logical operators are non-strict:
all subexpressions are not necessarily evaluated. Similarly, a generator function is
also non-strict. We can also call this eager vs. lazy. Python is generally eager but we
can leverage generator functions to create lazy evaluation.
While functional programming relies on recursion instead of explicit loop state,
Python imposes some limitations here. Because of the stack limitation and the lack
of an optimizing compiler, we're forced to manually optimize recursive functions.
We'll return to this topic in Chapter 6, Recursions and Reductions.