Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Programming Paradigms  ›  Lesson

Functional Programming and Pure Functions

Functional Programming 15 minFunctional programming builds programs from pure functions that return new values instead of changing shared state.

Functional Programming and Pure Functions

A Shelfwise test for add_tax passes in the morning and fails in the evening. The code has not changed. The reason: add_tax quietly reads the current region from a global setting and writes the new total into the cart. Functional programming is a way of writing code where that kind of surprise cannot happen.

The rule

Same input, same output, and nothing else touched.

That describes a pure function:

  1. Same input, same output. Its result depends only on its arguments, not on the clock, a global or a database.
  2. Nothing else touched. It has no side effects: it does not change its arguments, write files, print, or save.
# Impure: hidden input and two side effects
def add_tax(cart):
    cart.total = cart.total * (1 + TAX_RATES[current_region()])
    save(cart)

# Pure: everything it needs comes in, one value goes out
def with_tax(total, rate):
    return total * (1 + rate)

Functional programming builds programs mostly out of pure functions, plus two more habits:

  • Immutable data. Instead of changing a value, make a new one: new_lines = lines + [line] rather than lines.append(line).
  • Functions as values. Pass functions to other functions. sorted(books, key=lambda b: b.price) hands sorted a small function that says how to compare.

A program still has to save orders and send emails, so side effects do not vanish. They move to the edges: a thin layer of impure code gathers inputs, calls pure functions to do the thinking, then writes the results out.

The payoff is testing and reasoning. A pure function needs no setup and no mocks: call it, compare the answer. It can never break because of what ran before it.

The shortcut

Ask two questions about any function. Does it read anything besides its arguments? Does it change anything besides its return value? Two "no"s mean it is pure.

Testing order_total for purityStep 1 of 4
  1. The code

    def order_total(lines): return sum(l.price * l.qty for l in lines)

The trap is the hidden read. A function that calls datetime.now() or reads a config value looks innocent but fails question one.

Drills

Answer fast — trust the rule.

quick drill

Which function is pure?

quick drill

def price_now(book): return book.price * exchange_rate_today() — is it pure?

quick drill

What is the main testing benefit of pure functions?

quick drill

Which line adds a book to a list without changing the original list?

Remember

  • Pure: same input, same output, and nothing else touched.
  • Two questions: hidden inputs? hidden outputs? Two "no"s mean pure.
  • Trap: the innocent-looking read of the clock or a global; push side effects to the edges.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainMake the total pure

This Shelfwise function is impure: def add_tax(cart): cart.total = cart.total * (1 + TAX_RATES[current_region()]); save(cart). Explain every reason it is impure and rewrite it as a pure function, saying where the removed work should go instead.