Tacit programming


Tacit programming, also called point-free style, is a programming paradigm in which function definitions do not identify the arguments on which they operate. Instead the definitions merely compose other functions, among which are combinators that manipulate the arguments. Tacit programming is of theoretical interest, because the strict use of composition results in programs that are well adapted for equational reasoning. It is also the natural style of some programming languages, including APL and its derivatives, and concatenative languages such as Forth. The lack of argument naming gives point-free style a reputation of being needlessly obscure, hence the epithet "pointless style".
Unix scripting uses the paradigm with pipes.

Examples

Python

Tacit programming can be illustrated with the following Python code. A sequence of operations such as the following:

def example:
return baz

... can be written in point-free style as the composition of a sequence of functions, without parameters:

from functools import partial, reduce
def compose:
return partial
example = compose

For a more complex example, the Haskell code p = . g can be translated as:
p = partial

Functional programming

A simple example is a program which computes the sum of a list of numbers. We can define the sum function recursively using a pointed style as:
sum = 0
sum = x + sum xs

However, using a fold, this can be replaced with:

sum xs = foldr 0 xs

And then the argument is not needed, so this simplifies to

sum = foldr 0

which is point-free.
Another example uses function composition:

p x y z = f z

The following Haskell-like pseudocode exposes how to reduce a function definition to its point-free equivalent:

p = \x -> \y -> \z -> f z
= \x -> \y -> f
= \x -> \y -> y
= \x -> f.

= \x ->
= \x -> . g) x
p = . g

Finally, to see a complex example imagine a map filter program which takes a list, applies a function to it, and then filters the elements based on a criterion

mf criteria operator list = filter criteria

It can be expressed point-free as

mf = . . filter
As suggested already, the points in point-free refer to the arguments, not to the use of dots; a common misconception.
A few programs have been written to automatically convert a Haskell expression to a point-free form.

APL family

In the language J, the same sort of point-free code occurs in a function made to compute the average of a list of numbers:
avg=: +/ % #
+/ sums the items of the array by mapping summation to the array. % divides the sum by the number of elements in the array.
Euler's formula expressed tacitly:

cos =: 2 o. ]
sin =: 1 o. ]
Euler =: ^@j. = cos j. sin

The same tacit computations expressed in Dyalog APL:

avg ← +⌿ ÷ ≢
cos ← 2 ○ ⊢
sin ← 1 ○ ⊢
EulerCalc← cos + 0j1 × sin ⍝ 0j1 is what's usually written as i
EulerDirect← *0J1×⊢ ⍝ Same as ¯12○⊢
⍝ Do the 2 methods produce the same result?
EulerCheck← EulerDirect=EulerCalc
EulerCheck ¯1 1 2 3
1 1 1 1
⍝ Yes, so far so good!

Stack-based

In stack-oriented programming languages, point-free methods are commonly used. For example, a procedure to compute the Fibonacci numbers might look like the following in PostScript:

/fib
def

Pipelines

Unix pipeline

In Unix scripting the functions are computer programs which receive data from standard input and send the results to standard output. For example,
sort | uniq -c | sort -rn
is a tacit or point-free composition which returns the counts of its arguments and the arguments, in the order of decreasing counts. The and are the functions, the and control the functions, but the arguments are not mentioned. The pipe | is the composition operator.
Due to the way pipelines work, it is normally possible only to pass one argument at a time in the form of a pair of standard input/output stream. Although extra file descriptors can be opened from named pipes, this no longer constitutes a point-free style.

jq

is a JSON-oriented programming language in which the | symbol is used to connect filters to form a pipeline in a familiar way. For example:
| add
evaluates to 3.
Although similar to Unix pipelines, jq pipelines allow the incoming data to be sent to more than one recipient on the RHS of the | as though in parallel. For example, the program add/length will compute the average of the numbers in an array, so that:
| add/length
evaluates to 1.5
Similarly:
|
evaluates to
A dot can be used to define an attachment point on the RHS, e.g.:
1 |
evaluates to
and similarly:
2 | pow
evaluates to 4 since pow is x to the power y.
Fibonacci sequence
A tacit jq program for generating the Fibonacci sequence would be:
| recurse | first
Here, is the initial pair to be taken as the first two items
in the Fibonacci sequence.
The alphabetic tokens are built-in filters: `first` and `last`
emit the first and last elements of their input arrays respectively;
and recurse applies a filter, f, to its input recursively.
jq also allows new filters to be defined in a tacit style, e.g.:
def fib: | recurse | first;
Composition of unary functions
In the section on Python in this article, the following Python definition is considered:

def example:
return baz

In point-free style, this can be written in Python as:
example = compose
In jq, the equivalent point-free definition would be:
def example: foo | bar | baz;