The laws hidden in your code: what associativity buys you

LLM-authored, human-reviewed

Proofs & logic

Every operation you use follows rules you rarely write down. Reorder an addition, and the answer stays the same. Build a string by appending parts, and the pair you combine first does not matter. Append to a list, and starting with the empty list has the same effect as starting from nothing. Those rules - associativity, identity, and the rest - are not arithmetic trivia. They are the contract that lets you refactor, split, and parallelize code safely. They also drive the algebraic-law exercises on this site, which apply them to operations real programs use: log concatenation, validation checks, permission masks, ledgers, queues, and vote tallies.

What a law is

A law is a universal claim about an operation. It holds for every input, not just the cases you tried. The substitution oracles check equivalence by sampling inputs. A law makes the stronger claim that a relationship holds for all inputs at once. The algebraic-law exercises give you an operation - “combine two log strings by concatenation”, “merge two permission masks with bitwise OR” - and ask whether it obeys the laws that make it a monoid. Know the laws, and your answer is a decision rather than a guess.

The laws of a monoid

A monoid is three laws worn as one. An operation combine over values of a type is a monoid when:

  1. Closure - combining two values always produces another value of the same kind. Concatenating two strings is a string; OR-ing two masks is a mask. The operation never escapes its type.
  2. Associativity - the grouping does not matter: combine(a, combine(b, c)) gives the same result as combine(combine(a, b), c). The parentheses can move freely.
  3. Identity - there is a value that does nothing: an identity such that combine(identity, x) and combine(x, identity) both equal x. The empty string for concatenation. Zero for addition. The empty list for append.

That is the whole definition. The exercises focus on the interesting half: deciding which real operations obey it. String concatenation is a monoid - "a" <> ("b" <> "c") is the same string either way, and "" is the identity. Boolean AND is a monoid when you read it as “all validations passed”: true is the identity, and the grouping does not matter. XOR is a monoid - the light-switch toggle - and its identity is false. Not everything qualifies. Subtraction is not associative ((5 - 3) - 2 is not 5 - (3 - 2)), and it has no identity that works on both sides.

What associativity buys you

Associativity has the biggest engineering payoff here. It makes the site’s refactoring practice safe. If an operation is associative, change the shape of the computation without changing its result - that is the definition of a refactoring. The running-totals refactoring exercise folds a list left-to-right. With an associative operation, the same answer comes from folding right-to-left or splitting the work across two workers and combining the results. Grouping does not matter. Non-associative operations remove that freedom. Floating-point addition looks associative but is not (rounding depends on order), so summing a list in a different order can change the answer.

The identity is the quieter half of the contract. Every accumulator needs a starting value, and the identity gives you the correct one: 0 for a sum, [] for a build, "" for a join. The refactoring double exercise starts its loop with o = []; that [] is the identity of the append operation doing the building. The empty value is not a blank space where the code has not started. It is the law’s way of saying “the value that changes nothing”.

The exercises practice recognition

The algebraic-law exercises use programmer-facing instances. Their names give them away: “String concatenation monoid”, “Boolean AND monoid (all validations passed)”, “Bitwise OR monoid (merge permission masks)”, “Offset ledger monoid (addition in disguise)”, “Queue-batch monoid (prove the laws carry over)”, “List monoid: ++ and []”. The skill is recognition. Given an operation in its working clothes - a log writer, a permission system, a light switch - can you see the monoid underneath? Can you state which law makes it one? Most of the combinators you write are monoids or near-monoids. The three laws turn “this feels safe to refactor” into “this is safe to refactor, because associativity holds”.

Why this matters here

The laws are the grammar underneath the site’s other skills. Refactoring “changes the shape, keeps the meaning” - that is an associative law in action. The substitution oracle’s equivalence checks ask whether two expressions mean the same thing. The laws are the equivalences that hold for every input, which makes them checkable in principle rather than by sampling alone. The monoid has the same shape as the recursion and induction articles’ code: an identity is the base case, and associativity is the step that says the combination order cannot hurt you. When an operation obeys its laws, stop checking and start reasoning - the exercises train exactly that reflex.

Where to go next

Related exercises

← Back to articles