Tacit programming

Last updated

Tacit programming, also called point-free style, is a programming paradigm in which function definitions do not identify the arguments (or "points") 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. [1] It is also the natural style of certain programming languages, including APL and its derivatives, [2] and concatenative languages such as Forth. The lack of argument naming gives point-free style a reputation of being unnecessarily obscure, hence the epithet "pointless style". [1]

Contents

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:

defexample(x):returnbaz(bar(foo(x)))

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

fromfunctoolsimportpartial,reducedefcompose(*fns):returnpartial(reduce,lambdav,fn:fn(v),fns)example=compose(foo,bar,baz)

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

p=partial(compose,partial(compose,f),g)

Functional programming

A simple example (in Haskell) is a program which computes the sum of a list of numbers. We can define the sum function recursively using a pointed style (cf. value-level programming) as:

sum(x:xs)=x+sumxssum[]=0

However, using a fold we can replace this with:

sumxs=foldr(+)0xs

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

sum=foldr(+)0

which is point-free.

Another example uses function composition:

pxyz=f(gxy)z

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

p=\x->\y->\z->f(gxy)z=\x->\y->f(gxy)=\x->\y->(f.(gx))y=\x->f.(gx)(*Heretheinfixcomposeoperator"."isusedasacurriedfunction.*)=\x->((.)f)(gx)=\x->(((.)f).g)xp=((.)f).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

mfcriteriaoperatorlist=filtercriteria(mapoperatorlist)

It can be expressed point-free [4] as

mf=(.map).(.).filter

Note that, as stated previously, the points in 'point-free' refer to the arguments, not to the use of dots; a common misconception. [5]

A few programs have been written to automatically convert a Haskell expression to a point-free form.

APL family

In J, the same sort of point-free code occurs in a function made to compute the average of a list (array) 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=:2o.]sin=:1o.]Euler=:^@j.=cosj.sin

(j. is a primitive function whose monadic definition is 0j1 times x and whose dyadic definition is x+0j1×y.) The same tacit computations expressed in Dyalog APL:

avg+÷cos2sin1EulerCalccos+0j1×sin⍝ 0j1 is what's usually written as i EulerDirect*0J1×⊢⍝ Same as ¯12○⊢ ⍝ Do the 2 methods produce the same result? EulerCheckEulerDirect=EulerCalcEulerCheck¯11231111⍝ Yes, so far so good!

Stack-based

In stack-oriented programming languages (and concatenative ones, most of which are stack based[ citation needed ]), point-free methods are commonly used. For example, a procedure to compute the Fibonacci numbers might look like the following in PostScript:

/fib{dupdup1eqexch0eqornot{dup1subfibexch2subfibadd}if}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 'sort' and 'uniq' are the functions, the '-c' and '-rn' control the functions, but the arguments are not mentioned. The pipe '|' is the composition operator.

Due to the way pipelines work, it is only normally possible 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

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:

   [1,2] | add

evaluates to 3. (Yes, the JSON array is a jq filter that evaluates to an array.)

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:

   [1,2] | add/length

evaluates to 1.5

Similarly:

   [1,2] | [length, add, add/length]

evaluates to [2,3,1.5]

A dot ('.') can be used to define an attachment point on the RHS, e.g.:

   1 | [., .]

evaluates to [1,1]

and similarly:

   2 | pow(.; .)

evaluates to 4 since pow(x;y) is x to the power y.

Fibonacci sequence

A tacit jq program for generating the Fibonacci sequence would be:

   [0,1] | recurse( [last, add] ) | first

Here, [0,1] is the initial pair to be taken as the first two items in the Fibonacci sequence. (The pair [1,1] could likewise be used for the variant definition.)

The alphabetic tokens are built-in filters: `first` and `last` emit the first and last elements of their input arrays respectively; and `recurse(f)` applies a filter, f, to its input recursively.

jq also allows new filters to be defined in a tacit style, e.g.:

   def fib: [0,1] | recurse( [last, add] ) | first;
Composition of unary functions

In the section on Python in this article, the following Python definition is considered:

defexample(x):returnbaz(bar(foo(x)))

In point-free style, this could be written in Python as:

example=compose(foo,bar,baz)

In jq, the equivalent point-free definition would be:

   def example: foo | bar | baz;

See also

Related Research Articles

<span class="mw-page-title-main">Euler's formula</span> Complex exponential in terms of sine and cosine

Euler's formula, named after Leonhard Euler, is a mathematical formula in complex analysis that establishes the fundamental relationship between the trigonometric functions and the complex exponential function. Euler's formula states that, for any real number x, one has

<span class="mw-page-title-main">Exponential function</span> Mathematical function, denoted exp(x) or e^x

The exponential function is a mathematical function denoted by or . Unless otherwise specified, the term generally refers to the positive-valued function of a real variable, although it can be extended to the complex numbers or generalized to other mathematical objects like matrices or Lie algebras. The exponential function originated from the operation of taking powers of a number, but various modern definitions allow it to be rigorously extended to all real arguments , including irrational numbers. Its ubiquitous occurrence in pure and applied mathematics led mathematician Walter Rudin to consider the exponential function to be "the most important function in mathematics".

In programming language theory, lazy evaluation, or call-by-need, is an evaluation strategy which delays the evaluation of an expression until its value is needed and which also avoids repeated evaluations.

Nial is a high-level array programming language developed from about 1981 by Mike Jenkins of Queen's University, Kingston, Ontario, Canada. Jenkins co-created the Jenkins–Traub algorithm.

In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function together with an environment. The environment is a mapping associating each free variable of the function with the value or reference to which the name was bound when the closure was created. Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.

Programming style, also known as coding style or code style, is a set of rules or guidelines that governs the layout of source code. Programming style may also refer an quality aspect of code that is interpreted subjectively.

In computer science, pattern matching is the act of checking a given sequence of tokens for the presence of the constituents of some pattern. In contrast to pattern recognition, the match usually has to be exact: "either it will or will not be a match." The patterns generally have the form of either sequences or tree structures. Uses of pattern matching include outputting the locations of a pattern within a token sequence, to output some component of the matched pattern, and to substitute the matching pattern with some other token sequence.

A function pointer, also called a subroutine pointer or procedure pointer, is a pointer referencing executable code, rather than data. Dereferencing the function pointer yields the referenced function, which can be invoked and passed arguments just as in a normal function call. Such an invocation is also known as an "indirect" call, because the function is being invoked indirectly through a variable instead of directly through a fixed identifier or address.

In functional programming, a monad is a structure that combines program fragments (functions) and wraps their return values in a type with additional computation. In addition to defining a wrapping monadic type, monads define two operators: one to wrap a value in the monad type, and another to compose together functions that output values of the monad type. General-purpose languages use monads to reduce boilerplate code needed for common operations. Functional languages use monads to turn complicated sequences of functions into succinct pipelines that abstract away control flow, and side-effects.

In some programming languages, eval, short for the English evaluate, is a function which evaluates a string as though it were an expression in the language, and returns a result; in others, it executes multiple lines of code as though they had been included instead of the line including the eval. The input to eval is not necessarily a string; it may be structured representation of code, such as an abstract syntax tree, or of special type such as code. The analog for a statement is exec, which executes a string as if it were a statement; in some languages, such as Python, both are present, while in other languages only one of either eval or exec is.

A concatenative programming language is a point-free computer programming language in which all expressions denote functions, and the juxtaposition of expressions denotes function composition. Concatenative programming replaces function application, which is common in other programming styles, with function composition as the default way to build subroutines.

Cilk, Cilk++, Cilk Plus and OpenCilk are general-purpose programming languages designed for multithreaded parallel computing. They are based on the C and C++ programming languages, which they extend with constructs to express parallel loops and the fork–join idiom.

In mathematics and in computer programming, a variadic function is a function of indefinite arity, i.e., one which accepts a variable number of arguments. Support for variadic functions differs widely among programming languages.

In computer science, function composition is an act or mechanism to combine simple functions to build more complicated ones. Like the usual composition of functions in mathematics, the result of each function is passed as the argument of the next, and the result of the last one is the result of the whole.

<span class="mw-page-title-main">JavaScript syntax</span> Set of rules defining correctly structured programs

The syntax of JavaScript is the set of rules that define a correctly structured JavaScript program.

<span class="mw-page-title-main">Python syntax and semantics</span> Set of rules defining correctly structured programs

The syntax of the Python programming language is the set of rules that defines how a Python program will be written and interpreted. The Python language has many similarities to Perl, C, and Java. However, there are some definite differences between the languages. It supports multiple programming paradigms, including structured, object-oriented programming, and functional programming, and boasts a dynamic type system and automatic memory management.

In functional programming, fold refers to a family of higher-order functions that analyze a recursive data structure and through use of a given combining operation, recombine the results of recursively processing its constituent parts, building up a return value. Typically, a fold is presented with a combining function, a top node of a data structure, and possibly some default values to be used under certain conditions. The fold then proceeds to combine elements of the data structure's hierarchy, using the function in a systematic way.

In computer programming, an anonymous function is a function definition that is not bound to an identifier. Anonymous functions are often arguments being passed to higher-order functions or used for constructing the result of a higher-order function that needs to return a function. If the function is only used once, or a limited number of times, an anonymous function may be syntactically lighter than using a named function. Anonymous functions are ubiquitous in functional programming languages and other languages with first-class functions, where they fulfil the same role for the function type as literals do for other data types.

This article describes the features in the programming language Haskell.

jq (programming language) Programming language for JSON

jq is a very high-level lexically scoped functional programming language in which every JSON value is a constant. jq supports backtracking and managing indefinitely long streams of JSON data. It is related to the Icon and Haskell programming languages. The language supports a namespace-based module system and has some support for closures. In particular, functions and functional expressions can be used as parameters of other functions.

References

  1. 1 2 Manuel Alcino Pereira da Cunha (2005) Point-free Program Calculation
  2. W. Neville Holmes, ed. (2006) Computers and People
  3. "Name code not values". Concatenative.org. Retrieved 13 September 2013.
  4. pipermail
  5. "Pointfree - HaskellWiki". wiki.haskell.org. Retrieved 2016-06-05.