liveBook · Manning

Algebraic law

As explained in Functional Programming in Scala, Second Edition

A law is a general equation or behavioral property that operations or their implementations are expected to satisfy.

An algebraic law states an equation or behavioral property that an API’s operations must satisfy. Treating an API as operations plus laws makes type-directed reasoning more like symbolic algebra: implementations may vary, but they must preserve the stated relationships. Writing laws explicitly exposes design choices that informal expectations can hide. section 7.3

A law often begins as a concrete identity and is then generalized. For parallel computations, mapping over a completed value should agree with completing the mapped value: unit(x).map(f) == unit(f(x)). Equivalence is observed by running both computations on any valid ExecutorService and comparing their Future results. This prevents unit or map from inspecting values and changing behavior for particular cases. section 7.3.1

unit(x).map(f) == unit(f(x))      #1
unit(x).map(id) == unit(id(x))    #2
unit(x).map(id) == unit(x)        #3
y.map(id) == y                    #4

Follow a specific mapping example through substitution of the identity function to obtain the simpler identity law y.map(id) == y. section 7.3.1

Laws guide API design and reasoning in several ways:

  • Constrain meaning and implementation choices, rather than merely document preferred results. section 7.3.1
  • Supply high-level properties suitable for automated property-based tests, separating behavior specifications from generated test cases. section 8.0
  • Reveal shared structure when analogous operations satisfy the same law across Par, Gen, List, LazyList, Option, and State. section 8.4
  • Support algebraic design: specify operations and their relationships before committing to a data representation. section 9.1

Associativity preserves sequencing

Two nested flatMap expressions can look different after expanding a for-comprehension, yet should behave alike. The monad associative law requires x.flatMap(f).flatMap(g) == x.flatMap(a => f(a).flatMap(g)). For Option, the law can be checked by expanding both sides for its only cases: None and Some(v). Recasting monadic functions as Kleisli arrows makes the same requirement a familiar associative composition equation. section 11.4.1 section 11.4.2

Laws can define an abstraction independently of representation. A functor is characterized by structure-preserving map, with identity and composition laws. A monad supplies a minimal set of combinators—such as unit and flatMap—and satisfies associativity and identity. The contract does not prescribe internal behavior; satisfying the laws grants access to derived combinators. section 11.5 section 11.7

The payoff is reusable, testable APIs. A minimal set of primitive operations plus law-respecting derived combinators reduces duplication, while algebraic structure can justify splitting computations into independently computed chunks and composing larger calculations from smaller ones. section 7.6 section 10.0

How Functional Programming in Scala, Second Edition covers it

How deep it goes
Develops concrete mapping and flatMap equations, derives identity, and proves associativity for Option through case expansion.
Examples
Uses Par mapping, ExecutorService result comparison, Option cases, parser identities, and generated Order values.
What it assumes
Builds from concrete Scala operations such as map and flatMap before naming functor and monad abstractions.
What you can do after
Evaluate/understand whether alternative implementations preserve stated API behavior and derive reusable operations from lawful primitives.
How it connects
Connects API algebras with property-based testing, parser combinators, functors, monads, monoids, and Kleisli composition.

Also explained in

Compare how 2 books explain algebraic law →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Programming in Scala, Second Edition. The section links point to the parts of the book it draws on.