The when Utility: A Point-Free If Statement

A higher-order function that only calls another function when a predicate passes, and a real console.log gotcha worth knowing before you go point-free.

September 10, 20262 min read16 / 27

Point-free style handles negation cleanly with not. A conditional call needs its own tool.

Naming the Piece You Already Know

A function that returns true or false has its own name: a predicate. qualifiesForBulk from the last post is a predicate. So is any unary function whose whole job is answering a yes-or-no question.

Now say you only want to print a shipping notice when an order actually qualifies:

JavaScript
function printIfEligible(order) { if (isEligibleForFreeShipping(order)) { printNotice(order); } }

This works, but it's back to being pointed, order gets named and threaded through explicitly.

The Utility: when

JavaScript
function when(fn, predicate) { return function (...args) { if (predicate(...args)) { return fn(...args); } }; } const printIfEligible = when(printNotice, isEligibleForFreeShipping);

when takes an action and a predicate, and returns a new function that only runs the action when the predicate passes on the same arguments. It's a functional stand-in for an if statement, small enough to pass around as a value instead of writing it out at every call site.

Pointed
JavaScript
function printIfEligible(order) { if (isEligibleForFreeShipping(order)) { printNotice(order); } }

order gets named and threaded through by hand.

Point-free
JavaScript
const printIfEligible = when(printNotice, isEligibleForFreeShipping);

Same behavior, no input ever named.

A Real Gotcha Worth Knowing

Point-free style tempts you to do this:

JavaScript
const log = console.log; log('hello'); // works in some environments, throws in others

console.log is a method that expects to be called on the console object. Assign it to a plain variable, and depending on the JavaScript environment, it can lose that connection and fail. The fix is binding it explicitly:

JavaScript
const log = console.log.bind(console);

Point-free style is about function shape, not about being careless with what a function actually depends on to run. This is exactly that: a case where the shape looks compatible, but something implicit, the object a method expects to be called on, doesn't survive the reassignment.

Two Ways to Reach the Same Answer

Finding a point-free definition for printIfEligible works either by comparing what happens at the call site, or by comparing the two function signatures directly, when(fn, predicate) returns something shaped exactly like printIfEligible itself. Both routes land on the same answer. Use whichever one your brain finds faster in the moment.

The next post pushes further still: composing more than one function into a single point-free definition at once.

Try It Yourself

Take any if statement in your own code that only calls one function when a condition passes, no else branch. Rewrite it as when(action, predicate) instead, then check: does calling the result read as clearly as the original if, or did point-free style just make it harder to follow? Both answers are useful information about where this technique actually helps.