Content deleted Content added
MOS:HEAD |
→Functional programming: base case before the recursive case |
||
(46 intermediate revisions by 29 users not shown) | |||
Line 1:
{{Short description|Programming
'''Tacit programming''', also called '''point-free style''', is a [[programming paradigm]] in which function definitions do not identify the [[parameter (computer science)|arguments]] (or "points") on which they operate. Instead the definitions merely [[function composition (computer science)|compose]] other functions, among which are [[Combinatory logic|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 logic|equational]] reasoning.<ref name="cunha2005">{{cite thesis |last1=Cunha |first1=Manuel Alcino Pereira da
[[Unix]] [[Command-line interface|scripting]] uses the paradigm with [[Pipeline (Unix)|pipes]].
==Examples==
===Python ===
Tacit programming can be illustrated with the following [[Python (programming language)|Python]] code. A sequence of operations such as the following:
<syntaxhighlight lang="python">
def example(x):
</syntaxhighlight>
... can be written in point-free style as the composition of a sequence of functions, without parameters:<ref>{{cite web |url=http://concatenative.org/wiki/view/Concatenative%20language/Name%20code%20not%20values |title=Name code not values |publisher=Concatenative.org |access-date=13 September 2013}}</ref>
<
from functools import partial, reduce
def compose(*fns):
return
example = compose(
</syntaxhighlight>
For a more complex example, the [[Haskell]] code <code>p = ((.) f) . g</code> can be translated as:
p = partial(compose, partial(compose, f), g)
===Functional programming===
A simple example (in [[
<
sum (x:xs) = x + sum xs</syntaxhighlight>
However,
<
sum xs = foldr (+) 0 xs
</syntaxhighlight>
And then the argument is not needed, so this
<
sum = foldr (+) 0
</syntaxhighlight>
which is point-free.
Another example uses [[function composition (computer science)|function composition]]:
<
p x y z = f (g x y) z
</syntaxhighlight>
The following Haskell-like
<
p = \x -> \y -> \z -> f (g x y) z
= \x -> \y -> f (g x y)
= \x -> \y -> (f . (g x)) y
= \x -> f . (g x)
(* Here the infix compose operator "." is used as a curried function. *)
= \x -> ((.) f) (g x)
= \x -> (((.) f) . g) x
p = ((.) f) . g
</syntaxhighlight>
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 (map operator list)
</syntaxhighlight>
It can be expressed point-free<ref>[http://www.haskell.org/pipermail/haskell-cafe/2006-September/017758.html pipermail]</ref> as
<
mf = (. map) . (.) . filter
</
A few programs have been written to automatically convert a Haskell expression to a point-free form.
===APL family===
In the language [[J (programming language)|J]], the same sort of point-free code occurs in a function made to compute the average of a list (array) of numbers:
<
<code>+/</code> sums the items of the array by mapping (<code>/</code>) summation (<code>+</code>) to the array. <code>%</code> divides the sum by the number of elements (<code>#</code>) in the array.
[[Euler's formula]] <math>e^{ix} = \cos x + i\sin x,</math> expressed tacitly:
<
cos =: 2 o. ]
sin =: 1 o. ]
Euler =: ^@j. = cos j. sin
</syntaxhighlight>
(<code>j.</code> is a primitive function whose monadic definition is <code>0j1</code> times x and whose dyadic definition is <code>x+0j1×y</code>.) The same tacit computations expressed in [[APL_(programming_language)#Dyalog_APL|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!
</syntaxhighlight>
===Stack-based===
In [[stack-oriented programming language]]s (and [[concatenative programming language|concatenative ones]], most of which are stack based{{cn|date=January 2020}}), point-free methods are commonly used. For example, a procedure to compute the [[Fibonacci number]]s might look like the following in [[PostScript]]:
<
</syntaxhighlight>
===
====Unix pipeline====
{{Further|Pipeline (Unix)}}
In Unix scripting the functions are computer programs which receive data from [[Standard streams|standard input]] and send the results to [[Standard streams|standard output]].
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.
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 descriptor]]s can be opened from [[named pipe]]s, this no longer constitutes a point-free style.
====jq====
[[jq (programming language)|jq]] is a [[JSON]]-oriented programming language in which the <code>|</code> 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 <code>|</code> as though in parallel. For example, the program <code>add/length</code> 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 (<code>.</code>) 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 <code>pow(x;y)</code> 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, <code>[0,1]</code> is the initial pair to be taken as the first two items
in the Fibonacci sequence. (The pair <code>[1,1]</code> 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 <code>recurse(f)</code> 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:
<syntaxhighlight lang="python">
def example(x):
return baz(bar(foo(x)))
</syntaxhighlight>
In point-free style, this can 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 ==
Line 130 ⟶ 198:
* [[Function-level programming]]
* [[Joy (programming language)]], modern highly tacit language
==References==
Line 136 ⟶ 203:
==External links==
* [https://function-level.github.io/ From Function-Level Programming to Pointfree Style]
* [http://portal.acm.org/citation.cfm?id=114065&dl=GUIDE&coll=GUIDE Pure Functions in APL and J] How to use tacit programming in any APL-like language
* [http://dirkgerrits.com/publications/john-backus.pdf#section.8 Closed applicative languages 1971 - 1976 ff], in John W. Backus (Publications)
{{Programming paradigms navbox}}
[[Category:Programming paradigms]]
[[Category:Programming language comparisons]]
<!-- Hidden categories below -->
[[Category:Articles with example Haskell code]]
[[Category:Articles with example Python (programming language) code]]
|