The monad associativity law says that chaining two sequential computations does not depend on how the chain is parenthesized. For computations `f: A => F[B]`, `g: B => F[C]`, and `h: C => F[D]`, composing `f` with `g` and then with `h` has the same meaning as composing `f` with the result of composing `g` with `h`. section 11.7
From composition to flatMap
The composition statement can be unfolded step by step: ```scala compose(f, compose(g, h)) == compose(compose(f, g), h) ``` After expanding `compose`, both sides reduce to the same operational form: ```scala x.flatMap(b => g(b).flatMap(h)) == x.flatMap(g).flatMap(h) ``` The left side keeps the second binding inside the function passed to the first `flatMap`; the right side performs the bindings in two successive calls. Associativity guarantees that these two arrangements produce the same result. section 11.7
This law matters because it permits refactoring a monadic computation without changing its overall computed result. The same reasoning applies across different monads, provided their operations satisfy the monad laws. section 11.6 section 11.7
