Word count seems like an integer reduction until input is split at an arbitrary character boundary. Splitting "lorem ipsum dolor sit amet, " into "lorem ipsum do" and "lor sit amet, " must count dolor once, not zero or twice. An integer loses the unfinished fragments needed to combine those results correctly. section 10.4
Represent an intermediate result as either `Stub(chars)`, containing no confirmed whole words, or `Part(lStub, words, rStub)`, containing a confirmed count plus unfinished left and right fragments. Thus `"lorem ipsum do"` becomes `Part("lorem", 1, "do")`: only `ipsum` is certainly complete. section 10.4
enum WC: case Stub(chars: String) case Part(lStub: String, words: Int, rStub: String)
`WC` preserves precisely the boundary information that a plain `Int` discards. section 10.4
The combining operation preserves character order. Two stubs concatenate. Combining a stub and a part extends the part’s outer fragment. Combining two parts adds their confirmed counts and counts the joined inner fragments as one word when that joined string is nonempty. This makes independently reduced substrings composable. section 10.9
A correct empty value and reduction complete the count:
- Use `Stub("")` as the monoid identity. Using `Part("", 0, "")` fails identity because combining it with a stub changes the result’s representation. section 10.9
- Map each non-whitespace character to a `Stub`; map whitespace to an empty `Part`, so whitespace establishes a word boundary. section 10.9
- Fold an `IndexedSeq[Char]` with `foldMapV`, then count nonempty outer stubs along with the confirmed `words` field. section 10.9
- Check associativity and identity with generated `WC` values before trusting the implementation. section 10.9
Counting across a split word
The left substring produces `Part("lorem", 1, "do")`; the right produces `Part("lor", 2, "")`. Combining them joins `do` and `lor`, adds one completed word, and retains the outer stubs. The final result includes lorem, ipsum, dolor, sit, and amet. section 10.4 section 10.9
The central design move is to make uncertainty explicit. A monoid result need not be the final answer at every stage; it can carry enough local context for associative combination, then be interpreted as an `Int` only after the complete input has been folded. section 10.4 section 10.9

