A primitive is a foundational operation supplied directly by an abstraction’s interface. Other operations are derived by composing those primitives, so the interface exposes a small core while retaining expressive power. section 7.6 section 7.1.3
Designing an API means testing what its primitives can express. Start with concrete examples, assemble them from existing operations, notice repeated patterns, and factor those patterns into combinators. This process helps avoid ad hoc features that fit only the first examples. section 8.1.4
The distinction becomes concrete across several functional interfaces:
- For parallel computations, unit and fork are primitive operations, while lazyUnit is derived as fork(unit(a)). section 7.1.3
- For generators, a small representation can support choose, unit, boolean, and listOfN while inviting tests of which operations are genuinely necessary. section 8.1.4
- For parsers, primitives include string, regex, slice, label, scope, flatMap, attempt, and choice; larger parsers are built from them. section 9.6
Primitive versus derived operation
Given def unit[A](a: A): Par[A] and fork, define def lazyUnit[A](a: => A): Par[A] = fork(unit(a)). The new operation adds useful behavior without requiring direct knowledge of Par’s representation. That independence is the practical value of a well-chosen primitive boundary. section 7.1.3
def unit[A](a: => A): Gen[A] #1 def boolean: Gen[Boolean] extension [A](self: Gen[A]) def listOfN[A](n: Int): Gen[List[A]] #2
Inspect the generator interface to compare a compact primitive set with derived operations such as listOfN. section 8.1.4
