Composing Toward a Point-Free Definition

Why argument order matters for ergonomics, what function composition actually means, and how it closes the last gap in point-free style.

September 10, 20262 min read17 / 27

Everything so far has adapted or negated a single function. This post chains two together, which needs one more idea first.

Order Arguments for How They'll Actually Be Used

Here are two small utilities, the kind you'd find in any functional library:

JavaScript
function gte(threshold) { return function (amount) { return amount >= threshold; }; } function getSubtotal(order) { return order.items.reduce((sum, item) => sum + item.price, 0); }

gte takes its threshold first, then the amount to check, one at a time. That order isn't random. The value that stays fixed across many calls should come first; the value that changes every time should come last. gte(50) reads naturally as "at least 50," a specific, reusable check. Reverse the order, and every call site would need to repeat the threshold instead of settling it once.

gte(50) also previews an idea this series names properly later: pre-filling one input of a general function creates a more specific one. gte is general-purpose; gte(50) is a specific "is this at least 50" check with the general machinery hidden behind it.

Writing the Check, One Step at a Time

A cart qualifies for free shipping once its subtotal clears 50:

JavaScript
function qualifiesForFreeShipping(order) { return gte(50)(getSubtotal(order)); }

This works, and it's halfway to point-free. order still gets named and threaded through by hand.

Naming the Pattern: Composition

Look at what's actually happening: getSubtotal(order)'s output becomes the input to gte(50). One function's output feeding directly into another function's input has its own name: composition.

orderinput
getSubtotalstep 1
gte(50)step 2
true / falseoutput
JavaScript
function compose(fn2, fn1) { return function (...args) { return fn2(fn1(...args)); }; }

compose(fn2, fn1) runs fn1 first, then feeds its result into fn2. With that in hand, qualifiesForFreeShipping finally goes fully point-free:

JavaScript
const qualifiesForFreeShipping = compose(gte(50), getSubtotal);

No order in sight anywhere in that definition, and the function still does exactly what it did before.

Verifying It With the Same Reasoning as Always

This isn't a new trick, it's equational reasoning again. compose(gte(50), getSubtotal) and qualifiesForFreeShipping both take one order and return one true-or-false answer, the same shape, which is exactly what makes them interchangeable.

Composition is genuinely one of the biggest ideas in this entire series, and this was only a first look at it. It gets its own dedicated chapter much later, once more of the pieces it depends on are in place. For now, the takeaway is smaller and just as useful: once you can name a value flowing from one function straight into another, a point-free definition is usually one compose call away.

That's also where the Point-Free chapter ends. Next, this series turns to closure, the mechanism quietly doing the work every time a function like gte(50) remembers the value it was given.