A side effect is work a computation performs beyond producing its return value: changing data or state, interacting with memory or external systems, or carrying out input and output. Imperative programming permits such actions as part of step-by-step control flow; they can serve low-level goals such as cache-efficient execution, but they also make behavior depend on more than a function’s arguments. section 1.4.1 section 7.0
The central design question is not whether effects exist, but where they belong and how explicitly they are handled. Shared mutable state is identified as a major source of bugs in concurrent or parallel code. Functional design therefore favors immutability, avoids shared mutation, and treats a pure function as one that uses arguments to compute a result without mutating state or producing side effects. section 1.5 section 1.5.1
Keeping computation pure changes what can be relied on:
- The same arguments yield the same result, making a pure computation deterministic. section 1.5.1
- Composing pure functions preserves purity, allowing larger computations to remain predictable. section 1.5.1
- Separating effects from pure logic makes evaluation flow clearer and reduces the class of bugs caused by shared mutable state. section 1.5.1 section 1.6
Compute first, perform the effect separately
A maximum function can remain pure: it accepts two numbers and returns the larger one. Printing that result is a distinct IO routine. A third routine sequences the two: calculate the maximum, then print it. This division preserves a reusable deterministic calculation while making the observable action explicit in its result type. section 1.5.1
Some languages make the boundary visible in types. Haskell, PureScript, and Idris distinguish ordinary result types from effectful types such as IO or Effect, so an impure call inside a function declared to return a plain value fails to compile. Scala is contrasted as permitting an effectful call inside a function with an ordinary return type, without compiler restriction. section 1.5.1
Effects need not be scattered through application logic. A free-monad scenario can be a pure value that describes actions, while an interpreter later executes those actions. This decouples computation from interpretation, permits mocked or alternate effect implementations, and supports running the same logic in testing and production contexts. section 6.2.1
Functional programming does not require abandoning state or effects. It instead aims to organize them so they do not undermine immutability, reasoning, modularity, or testability. This makes careful effect handling a design concern alongside low coupling, high cohesion, interfaces, and modularity. section 7.0 section 1.6























