Functional style
Functional style builds programs from small pure functions that turn inputs into outputs and change nothing else. Follow a list of four numbers through a pipeline of map, filter and reduce, each step making a new list, and compare it with a loop that keeps rewriting one variable.
5 quick questions
Pick an answer to see why. Your score saves with your progress.
01Which of these functions is pure?
add only reads its inputs and returns a result. log prints (a side effect), push changes the list it was given, and roll can return different values for the same (empty) input.
02What does reduce(lambda a, b: a + b, [6, 8, 1]) return?
reduce combines the list into one value, left to right: first 6 + 8 = 14, then 14 + 1 = 15. 48 would be multiplying, and it never returns a list here.
03What is the difference between map(double, xs) and map(double(), xs)?
Without round brackets (), double is the function as a value, which map can call later. With () Python calls it immediately, and double needs an x, so it raises a TypeError.
04Which list comprehension does the same as list(filter(lambda n: n % 2 == 0, nums))?
The if part keeps only the values that pass the test, just like filter. The first option would give a list of True and False values instead.
05Why is a pure function like double easy to test, and safe to run on several processor cores at once?
To test double you call double(3) and check for 6: no setup, no other state to inspect. The same independence lets the calls run at once. Python lists are mutable; the pipeline just never changes them.
Glossary
- Pure function
- A function whose result depends only on its inputs and which has no side effects: the same input always gives the same output.
- Side effect
- Anything a function does besides returning a value, such as printing, changing a global variable or editing a list it was given.
- Immutability
- Never changing data once it is made; new values are built instead. A tuple is immutable in Python; a list is not, but you can choose not to change it.
- Function as a value
- Using a function's name without round brackets () to store it or pass it to another function, as in map(double, xs).
- lambda
- A small function written inline with one expression and no name, such as lambda y: y > 4.
- map, filter, reduce
- map applies a function to every value; filter keeps the values that pass a test; reduce combines all the values into one.
- List comprehension
- Python's short form for building a list from another, such as [x * 2 for x in xs if x > 1].
Notes and sources
- In Python 3, map and filter return lazy iterators that make each value only when asked; wrapping them in list(...) runs them and stores the results in a new list.
- reduce lives in the functools module, which is why line 1 imports it. For adding numbers, the built-in sum(zs) does the same job and is easier to read.
- A Python list is mutable: xs[0] = 9 would change it in place. Functional style simply never does that. A tuple such as (3, 1, 4, 2) is immutable: Python refuses to change it.
- A lambda holds a single expression. The PEP 8 style guide recommends a def instead of a lambda when you want to give the function a name.
- Running calls in parallel needs a tool such as concurrent.futures.ProcessPoolExecutor, and for four tiny numbers it would be slower than a plain loop. The point is that pure calls are safe to split up. The example must run from a .py file: the Python docs say ProcessPoolExecutor will not work in the interactive interpreter.
- Python HOWTO: Functional Programming
- Python library: Built-in functions (map, filter)
- Python library: functools.reduce
- Python reference: Lambdas
- Python tutorial: List comprehensions
- Python library: Immutable sequence types
- Python library: concurrent.futures
- Composing Programs 1.2: Elements of Programming (pure functions)
- Composing Programs 1.6: Higher-Order Functions
- PEP 8: Programming recommendations (lambda)
Quiz Unlocks after the last step.