Functional-programming Patterns Reference
Intent, fit, trade-offs, and relationships for reusable functional techniques.
Updated 2026-07-22
Pure Function
Return a result determined only by inputs without observable side effects.
| Aspect | Guidance |
|---|---|
| Use when | Logic should be predictable, testable, cacheable, and safely composable. |
| Trade-offs | Real programs still need effects, so boundaries and effect descriptions must be explicit. |
| Related | Immutability, Memoization |
Immutability
Represent a change by producing a new value rather than modifying an existing one.
| Aspect | Guidance |
|---|---|
| Use when | Values are shared, compared, replayed, or processed concurrently. |
| Trade-offs | Naive copying costs memory; APIs and data structures must support efficient updates. |
| Related | Persistent Data Structure, Lens |
Higher-order Function
Accept functions as inputs or return functions as results.
| Aspect | Guidance |
|---|---|
| Use when | Behavior should be abstracted from traversal, timing, policy, or data shape. |
| Trade-offs | Deep callback layers and abstract signatures can reduce readability. |
| Related | Function Composition, Closure |
Function Composition
Create a transformation by feeding each function’s result to the next.
| Aspect | Guidance |
|---|---|
| Use when | A workflow can be expressed as small compatible transformations. |
| Trade-offs | Types, error channels, and asynchronous boundaries must align. |
| Related | Pipeline, Higher-order Function |
Pipeline
Pass a value through a readable ordered sequence of transformations.
| Aspect | Guidance |
|---|---|
| Use when | Data processing is naturally staged from input to output. |
| Trade-offs | Branching, shared context, and mixed sync/async steps weaken a simple pipeline. |
| Related | Function Composition, Pipes and Filters |
Currying
Transform a multi-argument function into a series of one-argument functions.
| Aspect | Guidance |
|---|---|
| Use when | Functions should be specialized incrementally or composed in unary APIs. |
| Trade-offs | Calling conventions become unfamiliar and language support varies. |
| Related | Partial Application, Closure |
Partial Application
Create a new function by fixing some arguments of an existing function.
| Aspect | Guidance |
|---|---|
| Use when | Repeated calls share configuration or dependencies. |
| Trade-offs | Hidden bound values can make behavior and signatures less obvious. |
| Related | Currying, Dependency Injection |
Closure
Combine a function with values captured from its lexical environment.
| Aspect | Guidance |
|---|---|
| Use when | Behavior needs private state or configuration without a class. |
| Trade-offs | Captured mutable state, memory retention, and stale values can surprise callers. |
| Related | Higher-order Function, Partial Application |
Memoization
Cache function results by input so repeated calls reuse prior work.
| Aspect | Guidance |
|---|---|
| Use when | A pure computation is expensive and inputs repeat. |
| Trade-offs | Key equality, memory growth, invalidation, and sensitive inputs require policy. |
| Related | Pure Function, Lazy Evaluation |
Map
Apply a function to each contained value while preserving structure.
| Aspect | Guidance |
|---|---|
| Use when | Every element needs the same independent transformation. |
| Trade-offs | Side effects inside mapping obscure evaluation order and intent. |
| Related | Functor, Filter, Fold |
Filter
Retain elements that satisfy a predicate.
| Aspect | Guidance |
|---|---|
| Use when | Selection should be expressed independently of traversal. |
| Trade-offs | Multiple filter passes may be less efficient than one composed fold. |
| Related | Map, Fold |
Fold
Collapse a structure into a result using a combining function and accumulator.
| Aspect | Guidance |
|---|---|
| Use when | Aggregation or traversal can be defined from one composable primitive. |
| Trade-offs | Direction, associativity, initial values, and short-circuit behavior matter. |
| Related | Map, Recursion |
Persistent Data Structure
Preserve previous versions while sharing unchanged structure with new versions.
| Aspect | Guidance |
|---|---|
| Use when | Immutable updates need practical memory and time costs. |
| Trade-offs | Constants, cache locality, and interoperability may differ from mutable structures. |
| Related | Immutability, Lens |
Lens
Compose a focused getter with an immutable updater for nested data.
| Aspect | Guidance |
|---|---|
| Use when | Deep immutable structures require reusable, type-safe access and updates. |
| Trade-offs | Optics terminology and abstractions can outweigh benefits for shallow models. |
| Related | Immutability, Function Composition |
Algebraic Data Type
Model data using explicit product and alternative cases.
| Aspect | Guidance |
|---|---|
| Use when | A finite set of valid states should be represented and checked exhaustively. |
| Trade-offs | Changing cases affects consumers and some languages emulate the feature awkwardly. |
| Related | Pattern Matching, Option, Result |
Pattern Matching
Select and bind behavior by the structural form of data.
| Aspect | Guidance |
|---|---|
| Use when | Code handles explicit variants or recursively shaped values. |
| Trade-offs | Non-exhaustive matches fail and large matches can centralize too much behavior. |
| Related | Algebraic Data Type, Visitor |
Option
Represent either a present value or explicit absence.
| Aspect | Guidance |
|---|---|
| Use when | Missing data is expected and should not use null or exceptions. |
| Trade-offs | Callers must unwrap or transform the context and nested options can become noisy. |
| Related | Result, Functor |
Result
Represent either a success value or a structured failure value.
| Aspect | Guidance |
|---|---|
| Use when | Failure is expected, recoverable, and part of a function contract. |
| Trade-offs | Error types and combination rules require design; unexpected defects still need another path. |
| Related | Option, Monad |
Functor
Apply an ordinary function to values inside a context while preserving that context.
| Aspect | Guidance |
|---|---|
| Use when | Many structures need a common map-like transformation. |
| Trade-offs | The abstraction helps only when laws and context behavior are understood. |
| Related | Map, Applicative |
Applicative
Combine independent computations that each occur inside a context.
| Aspect | Guidance |
|---|---|
| Use when | The structure of a computation is known without depending on earlier values. |
| Trade-offs | Less flexible than monadic sequencing and syntax support varies. |
| Related | Functor, Monad |
Monad
Sequence contextual computations where each next step depends on the prior result.
| Aspect | Guidance |
|---|---|
| Use when | Errors, state, async work, parsing, or effects need composable chaining. |
| Trade-offs | Abstraction, nested contexts, and language-specific notation raise the learning cost. |
| Related | Applicative, Result |
Recursion
Solve a problem by defining base cases and combining smaller instances.
| Aspect | Guidance |
|---|---|
| Use when | Data or computation is naturally recursive, such as trees or divide-and-conquer. |
| Trade-offs | Deep calls can exhaust the stack and missing progress causes nontermination. |
| Related | Fold, Tail Recursion |
Tail Recursion
Place the recursive call in final position so an implementation may reuse the stack frame.
| Aspect | Guidance |
|---|---|
| Use when | A recursive loop targets a runtime that guarantees tail-call optimization. |
| Trade-offs | Many common runtimes do not optimize it, and accumulator style can be less direct. |
| Related | Recursion, Trampoline |
Trampoline
Represent recursive continuation steps as values and execute them in a loop.
| Aspect | Guidance |
|---|---|
| Use when | Deep recursion must remain stack-safe without runtime tail-call optimization. |
| Trade-offs | Allocates step objects and complicates debugging and return types. |
| Related | Tail Recursion, Continuation |
Lazy Evaluation
Delay a computation until its value is demanded and optionally retain the result.
| Aspect | Guidance |
|---|---|
| Use when | Values may never be needed or infinite and expensive structures are useful. |
| Trade-offs | Timing, memory retention, error location, and performance become less predictable. |
| Related | Memoization, Generator |