Point-Free Refactor: When Repetition Reveals a Relationship
Why defining a function in terms of another one, even when it costs a few extra characters, can make a hidden relationship between them visible.
The last post deleted a wrapper because two functions happened to share a shape. This one is about deliberately creating that overlap, because of what it reveals.
Two Ways to Write the Same Thing
Say you have a function that checks whether a cart qualifies for a bulk discount:
function qualifiesForBulk(itemCount) {
return itemCount >= 10;
}Now you need the opposite check, whether a cart doesn't qualify. The direct way:
function tooFewForBulk(itemCount) {
return itemCount < 10;
}Mathematically fine. But there's a second option that costs a few more characters and buys something real:
function tooFewForBulk(itemCount) {
return !qualifiesForBulk(itemCount);
}Repetition Can Be the More Honest Choice
Writing itemCount < 10 a second time works, but it hides the fact that tooFewForBulk is nothing but the negation of qualifiesForBulk. Defining it in terms of the first function states that relationship directly, instead of leaving the reader to notice it's just flipped math.
This is worth saying plainly: "don't repeat yourself" is a good default, not a rule to follow blindly. Sometimes the repetitive-looking version is the one that actually explains itself.
Making It Point-Free
Once the relationship is explicit, a small higher-order function removes the last bit of noise:
function not(fn) {
return function (...args) {
return !fn(...args);
};
}
const tooFewForBulk = not(qualifiesForBulk);not takes a function and hands back its negation. tooFewForBulk no longer even mentions itemCount, the point, and it's still completely clear what it does: the opposite of qualifiesForBulk.
Explicit Isn't Always Clearer
Most engineers, asked whether code should be explicit or implicit, say explicit without hesitating. This example argues the opposite in one specific way.
Imperative code spells out every step. Declarative code hides the steps and states the relationship instead.
itemCount < 10 is explicit about the mechanics and says nothing about the relationship to qualifiesForBulk. not(qualifiesForBulk) hides the mechanics entirely and states the relationship outright. The detail that got hidden, how the negation actually happens, was never the part worth the reader's attention.
That's the real payoff of point-free style: not shorter code, a codebase where the relationships between functions are visible instead of buried in duplicated logic. The next post pushes this same idea one step further, into composing more than one function together at once.
Keep reading