Declarative programming expresses the result and meaningful transformations while hiding control details such as loops, assignments, and state management. It favors code that reads like a description of the desired computation rather than instructions for the machine. section 4.2
Declarative code commonly emphasizes:
- Unidirectional state transformations instead of explicitly describing every control-flow change. section 4.2
- Named functions and expressions that reveal each processing step. section 4.3.1
- Composition of small, pure functions that can be replaced or rearranged without changing results. section 4.3.1
- A focus on what should be accomplished rather than how execution proceeds; SQL provides a prominent example. section 4.2
Composing a word counter
An imperative implementation reads a file, decodes its buffer, splits the text, and counts the words through explicit statements. A declarative version names those transformations and composes them: `const countWordsInFile = compose(count, split, decode, read);` The resulting function expresses the pipeline while hiding the intermediate control flow. section 4.3.1
function computeBalance(address) {
let balance = Money.zero();
for (const block of ledger) {
if (!block.isGenesis()) {
for (const tx of block.data) {
if (tx.sender === address) {
balance = balance.minus(tx.funds);
}
else {
balance = balance.plus(tx.funds);
}
}
}
}
return balance.round();
}
Compare the explicit loops, conditionals, assignments, and mutable balance state in the imperative calculation with its declarative counterpart. section 4.2
const computeBalance = address =>
compose(
Money.round,
reduce(Money.sum, Money.zero()),
map(balanceOf(address)),
flatMap(prop('data')),
filter(
compose(
not,
prop('isGenesis')
)
),
Array.from
);
Trace the same balance calculation as a composed pipeline of filtering, mapping, flattening, reducing, and rounding. section 4.2













