Your team wants every log-parsing helper written point-free; where do you push back?
answer
- readers decide, not elegance
- ask what the name was doing
- forwarding only means the name is noise
- new routing combinators are the warning
- anonymous stages mean nothing is named
basics
~20 sWhere erasing the argument forces in combinators that only route the value around. Dropping a name that merely forwards removes noise; dropping a name that the body actually uses trades one clear word for machinery.
solid answer
~40 sThe test is what the name was doing. If the parameter is mentioned once purely to be handed to the first stage, it carries no information the stage names do not already carry, and deleting it leaves a definition that reads as a list of steps — that is the case where the style pays. Push back wherever the rewrite has to add a combinator that duplicates the value, reorders arguments, or picks between branches: that machinery exists only to compensate for the missing name, so you have replaced one word a reader understands with three they must decode. Push back too where the chain's stages are anonymous inline functions, because then nothing is named — neither the value nor the steps — and the definition says only that something happens three times.
code
pseudocode · 9 lines// worth it: the name existed only to be handed to the first stage
define extractLevel(line) = uppercase(trim(fourthField(line)))
define extractLevel = fourthField then trim then uppercase
// not worth it: the name has to be replaced by routing machinery
// fanOut(f, g)(v) = pair(f(v), g(v))
// dividePair(pair(a, b)) = divide(a, b)
define errorRate(counts) = divide(errorsOf(counts), totalOf(counts))
define errorRate = fanOut(errorsOf, totalOf) then dividePairgo deeper
Recognise that removing an argument name is a readability trade, not an improvement by default, and that the stage names have to carry what the removed name used to say.
Be able to look at a body and say what the parameter is doing — forwarding, or being used twice, or being branched on — and decide the rewrite from that.
Give a criterion a reviewer can apply to a diff rather than an opinion, and show it landing correctly on both the easy case and the routing case.
Frame the choice around who reads the code and what vocabulary you can assume, and accept that the answer differs between a shared module and a specialised one.
## The question the style is really answering Point-free style is a claim about a *reader*: that the argument's name told them nothing the stage names do not already tell them, so the definition is clearer without it. That claim is sometimes true and sometimes false, and which one it is can be read off the code. The decision is not about elegance or brevity, and it is emphatically not about line count — a point-free definition and its pointed twin are usually within a few characters of each other. ## When the name was noise The name is noise when the body's only use of it is to forward it. Consider a definition that takes a log line, pulls the fourth field, trims it and upper-cases it. The word `line` appears once, in the innermost call, and its entire contribution is to say "start here". The stages already say everything else: `fourthField` says what is extracted, `trim` and `uppercase` say what happens to it. Erase the name and you get a definition that reads as three steps in order — which is what the function is. Two conditions usually travel together in this happy case: - **Each stage has a domain name.** Not an inline anonymous function, but a named step a reader can look up. - **The chain is short enough to hold in the head** — roughly, few enough stages that you can say out loud what the value is at every boundary. ## When the name was the point The name earns its keep the moment the body does something with the parameter other than forwarding it. Three shapes recur: 1. **The value is used twice.** A ratio, a difference, a comparison between two projections of the same input. Erasing the name means introducing a combinator that feeds one value to two stages and another that consumes the pair. Two pieces of routing machinery have replaced one word. 2. **The stage needs more than the value.** An index, a separator, a limit. The rewrite means fixing those arguments first, which is fine once and tiresome when every stage needs it. 3. **The body branches on the value.** Choosing a stage based on what arrived is a decision, and pushing it into a combinator that takes both alternatives as functions hides the decision behind plumbing. There is also a fourth, quieter case: the stages themselves are anonymous. A chain of three inline functions with no names is not point-free style paying off; it is a definition with nothing named at all — not the argument, not the steps, not the intermediate values. ## A heuristic you can state in a review | What you see in the diff | Verdict | |---|---| | Parameter deleted, no new function introduced | Keep it — the name was pure forwarding | | Parameter deleted, one or more routing combinators added | Push back — the name was doing work | | Parameter deleted, stages are anonymous inline functions | Push back — name the stages first, then decide | | Parameter kept, chain named and reused | Fine — naming the chain is the win, the parameter is cheap | Stated as one sentence: **erase the argument only when the rewrite introduces nothing new.** That is checkable by looking at the diff, it does not depend on taste, and it lands on the right side of every case above. It is also honest about the limit — it says nothing about whether a nine-stage chain of well-named steps is a good idea, which is a separate question about how much a reader can hold. ## Why "shorter" is the wrong proxy A team that optimises for the shortest definition will accept the ratio rewrite, because `fanOut(errorsOf, totalOf) then dividePair` is not obviously longer than the pointed version. The cost is not in characters; it is in the number of unfamiliar things a reader must resolve before the definition means anything. One well-chosen parameter name is resolved instantly by anyone; a routing combinator is resolved only by someone who already knows the vocabulary. That asymmetry is the whole argument, and it is why the rule is about what the rewrite *adds*, never about what it removes.
- A colleague argues the point-free version is better because it is shorter. Why is that the wrong measure?Because the cost is not in characters but in how many unfamiliar things a reader must resolve. A parameter name is resolved instantly by anyone; a routing combinator only by someone who already knows the vocabulary. The two forms are usually within a few characters of each other anyway, so brevity cannot be what is actually being traded.
- Does the rule change for a chain of nine well-named stages with no routing machinery?The erasure rule still says yes — nothing new was introduced, so the argument name was forwarding only. But that is a different question from whether a nine-stage chain is readable at all. Judge the chain's length on whether you can say what the value is at every boundary, and split it where you cannot; naming the seam is the fix, not reinstating the parameter.
- The chain is three inline anonymous functions with no names. What do you ask for first?Names for the stages, before any discussion of the argument. With anonymous steps, neither the values nor the operations are labelled, so the definition says only that three things happen in order. Once each stage has a domain name, the question of whether the parameter still earns its keep becomes answerable — and usually answers itself.
A recipe that says "chop, sear, rest" needs no word for the onion; a recipe whose steps keep handing the onion back and forth needs the word, and inventing a gadget to pass it around instead is not an improvement.
saying these in an interview costs you the question
- Judges the rewrite by which version is shorter
- Calls every argument name noise on principle
- Accepts routing combinators as the price of a cleaner style
- Chains anonymous inline functions and calls that point-free
- Says readability is subjective so no rule is possible
- Treats stage count alone as the readability threshold