This is a card in Dave's Virtual Box of Cards.

Point-free programming

Created: 2023-03-08

One of the strengths of concatenative programming languages such as Forth is that they doesn’t require you to come up with names for stuff that is hard to name, especially intermediate values between steps.

This is often called point-free, implicit, or tacit programming.

Here’s an example from my talk-turned-page called Forth: The programming language that writes itself:

If I ask you to add these numbers:

2, 6, 1, 3, 7

Do you feel a need to name any of them? Even the running total? Probably not.

But imperative programming languages often force us to give these values names in order to work on them.

fn sum(numbers){
    total = 0;
    numbers.each(i){
        total += i
    }
    return total
}

While point-free programming lets you work on values without naming them, often using higher-order functions:

fn sum_pf{
    return map +
}

In this second pseudo-code example, the higher-order function map takes the function + as input and also the list of numbers passed implicitly to sum_pf.

(Or map returns a new function which, in turn, takes the list of numbers. The outcome is the same, but you can do interesting things with this second form.)

The calling style may also be different to reflect the change in style as well. Here’s a fully-named example with explicit names for everything and and explicit function argument:

var nums = [2, 6, 1, 3, 7]
var total = sum(nums)

And here’s a "concatenative" style with no names. The list of numbers has now been replaced with the total, ready to be acted upon, implicitly, by the next function:

[2, 6, 1, 3, 7] sum_pf

Taken too far, this "tacit style" can get really hard to understand. But there seems to be a Goldilocks place where it’s just right.

To the best of my knowledge, the language which takes tacit (no names) programming as far as anyone has yet seen is BQN (github.io) which is an APL-like for modern times.

Outside of programming languages, combinatory logic lets you use, essentially, nothing but functions acting on functions to express any computation. It’s completely unreadable (change my mind!) but pretty amazing to behold.

The combinator-heavy Joy (wikipedia.org) language uses unary functions (they all take and return a stack) and eliminates not only most names, but also most control structures - even elegantly abstracting out recursion.