- Use `camelCase` for function and variable names, `PascalCase` for type and constructor names, and `SCREAMING_SNAKE_CASE` for top-level constants.
- Write top-level type signatures for all exported functions — they serve as machine-checked documentation and catch type errors early.
- Prefer point-free style where it improves readability; avoid it when it makes the data flow harder to follow than explicit argument names.
- Use `where` clauses for local helpers in function definitions; use `let`-in for local bindings inside `do` blocks.
- Use `newtype` wrappers to give semantic meaning to primitive types — `newtype UserId = UserId Int` prevents passing an `OrderId` where a `UserId` is expected.
- Enable `{-# LANGUAGE ScopedTypeVariables #-}` to annotate types on local bindings and pattern variables inside polymorphic functions.
- Prefer `Data.Map.Strict` over `Data.Map.Lazy` for maps used as accumulators — lazy maps accumulate unevaluated thunks and cause space leaks.
- Group related functions in modules with explicit export lists to prevent unintended API surface exposure.