liveBook · Manning

Point-free style

As explained in The Joy of JavaScript

A functional programming style in which functions are composed without explicitly naming the intermediate argument being transformed.

Point-free style defines a function without naming the argument it will receive. Instead, curried functions and composition pass that argument through a sequence of operations. The result can read like an outline of the task rather than a record of each intermediate value. section 4.6

Count words without tracing intermediate variables

An imperative word counter names a file buffer, a decoded string, and an array of words. A point-free version states the operations: `const countWordsInFile = compose(count, split, decode('utf8'), read);`. When called with a file, `read` receives the argument first; the remaining functions run from right to left. section 4.6 section 4.3.1

The style is useful when named steps expose the intent of a pipeline. Removing parameter names reduces syntactic noise, but the component functions still need meaningful names: composition makes the overall logic easier to scan, not the individual operations unnecessary to understand. section 4.6

To compose array operations, extract methods into curried functions with the changing collection last: `const map = curry((f, arr) => arr.map(f));`. Then `map(balanceOf(address))` supplies the mapper now and receives the collection through `compose` later. An address can remain explicit when it configures the pipeline; the ledger need not be named inside it. section 4.7

Listing 4.18 Point-free version of computeBalance
const computeBalance = address =>
  compose(                              #1
    Money.round,
    reduce(Money.sum, Money.zero()),    #2
    map(balanceOf(address)),            #2
    flatMap(prop('data')),              #2
    filter(                             #2
      compose(                          #3
        not,
        prop('isGenesis')
      )
    ),
    Array.from
  );
 
const computeBalanceForSender123 = computeBalance('sender123');
computeBalanceForSender123(ledger); 

The balance pipeline converts a ledger to an array, excludes genesis blocks, extracts transactions, calculates amounts for one address, sums them, and rounds the result. Its address is fixed when the function is created; the ledger arrives at the call site. section 4.7

Ordinary `compose` sequences functions returning unwrapped values. When each step returns a monad such as `Validation`, `composeM` uses `flatMap` to pass values onward while flattening the container. This supports a point-free validation pipeline without treating wrapped and unwrapped results as interchangeable. section 5.5.6

How The Joy of JavaScript covers it

How deep it goes
Develops tacit definitions through composition and curried array helpers, then extends them to monads while deferring detailed monadic composition derivation.
Examples
Contrasts imperative and composed file word counts, builds a wallet-balance pipeline, and chains block-validation checks.
What it assumes
Assumes JavaScript functions and array operations while introducing composition and currying before applying point-free design.
What you can do after
Build it from scratch by currying reusable operations and composing them into functions that accept their changing input at the call site.
How it connects
Connects function composition and currying with declarative programming, array processing, monads, and validation.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of The Joy of JavaScript. The section links point to the parts of the book it draws on.