liveBook · Manning

Determinism

As explained in Functional Design and Architecture: Examples in Haskell

Determinism is the property that the same inputs and conditions produce a predictable, uniquely determined result.

Deterministic behavior means that the same inputs, under the same conditions, produce the same result. It makes code predictable: a calculation called today and again later with identical arguments should return the identical value. In functional design, pure functions provide this property because they use arguments to produce results without side effects or mutation. section 1.5.1

Avoiding mutable shared state removes a major source of nondeterminism, especially in parallel code. Imperative updates can be necessary, but they make results depend on evaluation order or outside state. A composition of pure functions remains pure, so a larger functional pipeline can retain predictable behavior at every level. section 1.5.1 section 1.2.1

def max(a: Float, b: Float) : Float = {
 math.max(a, b)
}
  
def calc(a: Int, b: Int, c: Float) : Float = {
 val sum = a + b
 val average = sum / 2
 max(average, c)
}

This calculation forms a small pure pipeline: it derives a sum and average from its arguments, then returns a maximum. Reusing a, b, and c produces the same result because no external state is read or changed. section 1.5.1

Language support can make purity easier to recognize or enforce. Haskell, PureScript, and Idris distinguish effectful computations through types such as IO or Effect, so an effectful call cannot fit inside a function declared to return a plain Float. Scala permits side effects in an ordinary function body, leaving that discipline to design and review. section 1.5.1

Determinism supports testing, but it does not eliminate every risk:

  • A deterministic unit can be evaluated in a test environment with an expectation that its behavior resembles its behavior elsewhere. section 15.1
  • Pure functions can be tested directly against representative and edge-case inputs. section 15.1.1
  • Tests should arrange data, perform one action, and assert one result while remaining independent of other tests. section 15.1.1
  • Shared effectful state can make parallel tests race: outcomes may depend on whether a write or read occurs first. section 15.1.1

Testing a deterministic function

A square function can be checked with positive, negative, and zero inputs: 2 maps to 4, -2 maps to 4, and 0 maps to 0. These assertions are reliable because the function has no hidden state to change its answer. By contrast, tests that share an IORef can interfere with one another when run in parallel; isolate effects and separate concerns before testing them. section 15.1.1 section 15.1.1

Use deterministic behavior as a design goal when reasoning about correctness, concurrency, and testing. It reduces uncertainty rather than replacing testing: external services, effects, and integration concerns still require controlled, isolated tests and deliberate architecture. section 15.1 section 1.2.1

How Functional Design and Architecture: Examples in Haskell covers it

How deep it goes
Defines determinism through purity, composition, effect types, and testing consequences without formal semantics.
Examples
Uses a calc/max pipeline, Haskell effect signatures, square assertions, and IORef-dependent tests.
What it assumes
Assumes familiarity with functions and testing while illustrating pure calls, assertions, and shared-state hazards directly.
What you can do after
Evaluate/understand whether purity and isolated effects make code and tests predictably repeatable.
How it connects
Connects determinism with pure functions, immutability, shared state, side effects, concurrency, and testing.

Also explained in

Compare how 10 books explain determinism →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Design and Architecture: Examples in Haskell. The section links point to the parts of the book it draws on.