[go: nahoru, domu]

Combinatory logic: Difference between revisions

Content deleted Content added
m Brought all references to the alphabetical list and referenced them inline by {{sfn}} and {{harvtxt}}; removed redundant spaces and line feeds;
Line 2:
{{distinguish|text=[[combinational logic]], a topic in digital electronics}}
 
'''Combinatory logic''' is a notation to eliminate the need for [[Quantifier (logic)|quantified]] variables in [[mathematical logic]]. It was introduced by [[Moses Schönfinkel]]<ref>{{cite journal sfn|first=Moses |last=Schönfinkel |author-link=Moses Schönfinkel |year=1924 |urlloc=http://www.cip.ifi.lmu.de/~langeh/test/1924%20-%20Schoenfinkel%20-%20Ueber%20die%20Bausteine%20der%20mathematischen%20Logik.pdfThe |title=Überarticle diethat Bausteinefounded dercombinatory mathematischenlogic. LogikEnglish |journal=Mathematische Annalentranslation: {{harvtxt|volume=92 Schönfinkel|issue=3–4 |pages=305–316 |doi=10.1007/bf01448013|s2cid=118507515 1967}}}} Translated by Stefan Bauer-Mengelberg as "On the building blocks of mathematical logic" in [[Jean van Heijenoort]], 1967. ''A Source Book in Mathematical Logic, 1879&ndash;1931''. Harvard Univ. Press: 355&ndash;66.</ref> and [[Haskell Curry]],<ref>{{cite journalsfn|last=Curry|first=Haskell Brooks|title=Grundlagen der Kombinatorischen Logik|journal=American Journal of Mathematics|year=1930|volume=52|issue=3|pages=509–536|author-link=Haskell Curry|trans-title=Foundations of combinatorial logic|publisher=The Johns Hopkins University Press|language=de|doi=10.2307/2370619|jstor=2370619}}</ref> and has more recently been used in [[computer science]] as a theoretical [[model of computation]] and also as a basis for the design of [[functional programming languages]]. It is based on '''combinators''', which were introduced by [[Moses Schönfinkel|Schönfinkel]] in 1920 with the idea of providing an analogous way to build up functions—and to remove any mention of variables—particularly in [[predicate logic]]. A combinator is a [[higher-order function]] that uses only [[function application]] and earlier defined combinators to define a result from its arguments.
 
==In mathematics==
Combinatory logic was originally intended as a 'pre-logic' that would clarify the role of [[quantifier (logic)|quantified variables]] in logic, essentially by eliminating them. Another way of eliminating quantified variables is [[Willard Van Orman Quine|Quine's]] [[predicate functor logic]]. While the [[expressive power (computer science)|expressive power]] of combinatory logic typically exceeds that of [[first-order logic]], the expressive power of [[predicate functor logic]] is identical to that of first order logic ([[#Quine 1960 1966|Quine 1960, 1966, 1976]]).
 
The original inventor of combinatory logic, [[Moses Schönfinkel]], published nothing on combinatory logic after his original 1924 paper. [[Haskell Curry]] rediscovered the combinators while working as an instructor at [[Princeton University]] in late 1927.<ref name="Seldin 2006">{{cite websfn|last=Seldin|first=Jonathan|title=The Logic of Curry and Church|year=2008|url=http://people.uleth.ca/%7Ejonathan.seldin/CCL.pdf}}</ref> In the late 1930s, [[Alonzo Church]] and his students at Princeton invented a rival formalism for functional abstraction, the [[lambda calculus]], which proved more popular than combinatory logic. The upshot of these historical contingencies was that until theoretical computer science began taking an interest in combinatory logic in the 1960s and 1970s, nearly all work on the subject was by [[Haskell Curry]] and his students, or by [[Robert Feys]] in [[Belgium]]. Curry and Feys (1958), and Curry ''et al.'' (1972) survey the early history of combinatory logic. For a more modern treatment of combinatory logic and the lambda calculus together, see the book by [[Henk Barendregt|Barendregt]],{{sfn|Barendregt|1984}} which reviews the [[model theory|models]] [[Dana Scott]] devised for combinatory logic in the 1960s and 1970s.
<!-- This section needs a LOT of filling in!!! -->
 
==In computing==
Line 15 ⟶ 14:
Combinatory logic can be viewed as a variant of the [[lambda calculus]], in which lambda expressions (representing functional abstraction) are replaced by a limited set of ''combinators'', primitive functions without [[free variables and bound variables|free variable]]s. It is easy to transform lambda expressions into combinator expressions, and combinator reduction is much simpler than lambda reduction. Hence combinatory logic has been used to model some [[non-strict programming language|non-strict]] [[functional programming]] languages and [[graph reduction machine|hardware]]. The purest form of this view is the programming language [[Unlambda]], whose sole primitives are the S and K combinators augmented with character input/output. Although not a practical programming language, Unlambda is of some theoretical interest.
 
Combinatory logic can be given a variety of interpretations. Many early papers by Curry showed how to translate axiom sets for conventional logic into combinatory logic equations (.{{sfn|Hindley and |Meredith |1990).}} [[Dana Scott]] in the 1960s and 1970s showed how to marry [[model theory]] and combinatory logic.
 
== Summary of lambda calculus ==
{{main|Lambda calculus}}
 
Lambda calculus is concerned with objects called ''lambda-terms'', which can be represented by the following three forms of strings:
the following three forms of strings:
 
* {{tmath|v}}
Line 27 ⟶ 25:
* {{tmath|(E_1 E_2)}}
 
where {{tmath|v}} is a variable name drawn from a predefined infinite set of variable names, and {{tmath|E_1}} and {{tmath|E_2}} are lambda-terms.
variable names, and {{tmath|E_1}} and {{tmath|E_2}} are lambda-terms.
 
Terms of the form {{tmath|\lambda v.E_1}} are called ''abstractions''. The variable ''v'' is called the [[formal parameter]] of the abstraction, and {{tmath|E_1}} is the ''body'' of the abstraction. The term {{tmath|\lambda v.E_1}} represents the function which, applied to an argument, binds the formal parameter ''v'' to the argument and then computes the resulting value of {{tmath|E_1}}&mdash; that is, it returns {{tmath|E_1}}, with every occurrence of ''v'' replaced by the argument.
Terms of the form {{tmath|\lambda v.E_1}} are called ''abstractions''. The variable ''v'' is
called the [[formal parameter]] of the abstraction, and {{tmath|E_1}} is the ''body''
of the abstraction. The term {{tmath|\lambda v.E_1}} represents the function which, applied
to an argument, binds the formal parameter ''v'' to the argument and then
computes the resulting value of {{tmath|E_1}}&mdash; that is, it returns {{tmath|E_1}}, with
every occurrence of ''v'' replaced by the argument.
 
Terms of the form {{tmath|(E_1 E_2)}} are called ''applications''. Applications model function invocation or execution: the function represented by {{tmath|E_1}} is to be invoked, with {{tmath|E_2}} as its argument, and the result is computed. If {{tmath|E_1}} (sometimes called the ''applicand'') is an abstraction, the term may be ''reduced'': {{tmath|E_2}}, the argument, may be substituted into the body of {{tmath|E_1}} in place of the formal parameter of {{tmath|E_1}}, and the result is a new lambda term which is ''equivalent'' to the old one. If a lambda term contains no subterms of the form {{tmath|((\lambda v.E_1) E_2)}} then it cannot be reduced, and is said to be in [[Beta normal form|normal form]].
Terms of the form {{tmath|(E_1 E_2)}} are called ''applications''. Applications model
function invocation or execution: the function represented by {{tmath|E_1}} is to be
invoked, with {{tmath|E_2}} as its argument, and the result is computed. If {{tmath|E_1}}
(sometimes called the ''applicand'') is an abstraction, the term may be
''reduced'': {{tmath|E_2}}, the argument, may be substituted into the body of {{tmath|E_1}}
in place of the formal parameter of {{tmath|E_1}}, and the result is a new lambda
term which is ''equivalent'' to the old one. If a lambda term contains no
subterms of the form {{tmath|((\lambda v.E_1) E_2)}} then it cannot be reduced, and is said to
be in [[Beta normal form|normal form]].
 
The expression {{tmath|E[v :{{=}} a]}} represents the result of taking the term {{mvar|E}} and replacing all free occurrences of {{mvar|v}} in it with {{mvar|a}}. Thus we write
 
:{{tmath|((\lambda v.E) a) \Rightarrow E[v :{{=}} a]}}
Line 53 ⟶ 37:
By convention, we take {{tmath|(a b c)}} as shorthand for {{tmath|((a b) c)}} (i.e., application is [[Associative#Non-associativity|left associative]]).
 
The motivation for this definition of reduction is that it captures the essential behavior of all mathematical functions. For example, consider the function that computes the square of a number. We might write
the essential behavior of all mathematical functions. For example,
consider the function that computes the square of a number. We might
write
 
:The square of ''x'' is {{tmath|x*x}}
 
(Using "{{tmath|*}}" to indicate multiplication.) ''x'' here is the [[formal parameter]] of the function. To evaluate the square for a particular argument, say 3, we insert it into the definition in place of the formal parameter:
argument, say 3, we insert it into the definition in place of the
formal parameter:
 
:The square of 3 is {{tmath|3*3}}
 
To evaluate the resulting expression {{tmath|3*3}}, we would have to resort to our knowledge of multiplication and the number 3. Since any computation is simply a composition of the evaluation of suitable functions on suitable primitive arguments, this simple substitution principle suffices to capture the essential mechanism of computation.
Moreover, in lambda calculus, notions such as '3' and '{{tmath|*}}' can be represented without any need for externally defined primitive operators or constants. It is possible to identify terms in lambda calculus, which, when suitably interpreted, behave like the number 3 and like the multiplication operator, q.v. [[Church encoding]].
our knowledge of multiplication and the number 3. Since any
computation is simply a composition of the evaluation of suitable
functions on suitable primitive arguments, this simple substitution
principle suffices to capture the essential mechanism of computation.
Moreover, in lambda calculus, notions such as '3' and '{{tmath|*}}' can be
represented without any need for externally defined primitive
operators or constants. It is possible to identify terms in lambda calculus, which, when suitably interpreted, behave like the
number 3 and like the multiplication operator, q.v. [[Church encoding]].
 
Lambda calculus is known to be computationally equivalent in power to many other plausible models for computation (including [[Turing machine]]s); that is, any calculation that can be accomplished in any of these other models can be expressed in lambda calculus, and vice versa. According to the [[Church-Turing thesis]], both models can express any possible computation.
Lambda calculus is known to be computationally equivalent in power to
many other plausible models for computation (including [[Turing machine]]s); that is, any calculation that can be accomplished in any
of these other models can be expressed in lambda calculus, and
vice versa. According to the [[Church-Turing thesis]], both models
can express any possible computation.
 
It is perhaps surprising that lambda-calculus can represent any conceivable computation using only the simple notions of function abstraction and application based on simple textual substitution of terms for variables. But even more remarkable is that abstraction is not even required. ''Combinatory logic'' is a model of computation equivalent to lambda calculus, but without abstraction. The advantage of this is that evaluating expressions in lambda calculus is quite complicated because the semantics of substitution must be specified with great care to avoid variable capture problems. In contrast, evaluating expressions in combinatory logic is much simpler, because there is no notion of substitution.
It is perhaps surprising that lambda-calculus can represent any
conceivable computation using only the simple notions of function
abstraction and application based on simple textual substitution of
terms for variables. But even more remarkable is that abstraction is
not even required. ''Combinatory logic'' is a model of computation
equivalent to lambda calculus, but without abstraction. The advantage
of this is that evaluating expressions in lambda calculus is quite complicated
because the semantics of substitution must be specified with great care to
avoid variable capture problems. In contrast, evaluating expressions in
combinatory logic is much simpler, because there is no notion of substitution.
 
== Combinatory calculi ==
 
Since abstraction is the only way to manufacture functions in the lambda calculus, something must replace it in the combinatory calculus. Instead of abstraction, combinatory calculus provides a limited set of primitive functions out of which other functions may be built.
lambda calculus, something must replace it in the combinatory
calculus. Instead of abstraction, combinatory calculus provides a
limited set of primitive functions out of which other functions may be
built.
 
=== Combinatory terms ===
Line 116 ⟶ 71:
|}
 
The primitive functions are ''combinators'', or functions that, when seen as lambda terms, contain no [[free variable|free variables]]s.
 
To shorten the notations, a general convention is that {{tmath|(E_1 E_2 E_3 ... E_n)}}, or even {{tmath|E_1 E_2 E_3... E_n}}, denotes the term {{tmath|(...((E_1 E_2) E_3)... E_n)}}. This is the same general convention (left-associativity) as for multiple application in lambda calculus.
Line 130 ⟶ 85:
=== Examples of combinators ===
 
The simplest example of a combinator is '''I''', the identity combinator, defined by
combinator, defined by
 
:('''I''' ''x'') = ''x''
 
for all terms ''x''. Another simple combinator is '''K''', which manufactures constant functions: ('''K''' ''x'') is the function which, for any argument, returns ''x'', so we say
manufactures constant functions: ('''K''' ''x'') is the function which,
for any argument, returns ''x'', so we say
 
:(('''K''' ''x'') ''y'') = ''x''
 
for all terms ''x'' and ''y''. Or, following the convention for multiple application,
multiple application,
 
:('''K''' ''x'' ''y'') = ''x''
 
A third combinator is '''S''', which is a generalized version of application:
application:
 
:('''S''' ''x y z'') = (''x z'' (''y z''))
 
'''S''' applies ''x'' to ''y'' after first substituting ''z'' into
each of them. Or put another way, ''x'' is applied to ''y'' inside the environment ''z''.
environment ''z''.
 
Given '''S''' and '''K''', '''I''' itself is unnecessary, since it can be built from the other two:
be built from the other two:
 
:(('''S K K''') ''x'')
Line 165 ⟶ 113:
for any term ''x''. Note that although (('''S K K''')
''x'') = ('''I''' ''x'') for any ''x'', ('''S K K''')
itself is not equal to '''I'''. We say the terms are [[extensional equality|extensionally equal]]. Extensional equality captures the mathematical notion of the equality of functions: that two functions are ''equal'' if they always produce the same results for the same arguments. In contrast, the terms themselves, together with the reduction of primitive combinators, capture the notion of ''intensional equality'' of functions: that two functions are ''equal'' only if they have identical implementations [[up to]] the expansion of primitive combinators. There are many ways to implement an identity function; ('''S K K''') and '''I''' are among these ways. ('''S K S''') is yet another. We will use the word ''equivalent'' to indicate extensional equality, reserving ''equal'' for identical combinatorial terms.
itself is not equal to '''I'''. We say the terms are [[extensional equality|extensionally equal]]. Extensional equality captures the
mathematical notion of the equality of functions: that two functions
are ''equal'' if they always produce the same results for the same
arguments. In contrast, the terms themselves, together with the
reduction of primitive combinators, capture the notion of
''intensional equality'' of functions: that two functions are ''equal''
only if they have identical implementations [[up to]] the expansion of primitive
combinators. There are many ways to
implement an identity function; ('''S K K''') and '''I'''
are among these ways. ('''S K S''') is yet another. We
will use the word ''equivalent'' to indicate extensional equality,
reserving ''equal'' for identical combinatorial terms.
 
A more interesting combinator is the [[fixed point combinator]] or '''Y''' combinator, which can be used to implement [[recursion]].
Line 182 ⟶ 119:
=== Completeness of the S-K basis ===
 
'''S''' and '''K''' can be composed to produce combinators that are extensionally equal to ''any'' lambda term, and therefore, by Church's thesis, to any computable function whatsoever. The proof is to present a transformation, ''T''[&nbsp;], which converts an arbitrary lambda term into an equivalent combinator.
 
''T''[&nbsp;] may be defined as follows:
Line 197 ⟶ 134:
This process is also known as ''abstraction elimination''. This definition is exhaustive: any lambda expression will be subject to exactly one of these rules (see [[Combinatory logic#Summary of lambda calculus|Summary of lambda calculus]] above).
 
It is related to the process of ''bracket abstraction'', which takes an expression ''E'' built from variables and application and produces a combinator expression [x]E in which the variable x is not free, such that [''x'']''E x'' = ''E'' holds. A very simple algorithm for bracket abstraction is defined by induction on the structure of expressions as follows:{{sfn|Turner|1979}}
A very simple algorithm for bracket abstraction is defined by induction on the structure of expressions as follows:<ref name="Turner 1979">{{cite journal|last=Turner|first=David A.|author-link=David Turner (computer scientist)|title=Another Algorithm for Bracket Abstraction|journal=The Journal of Symbolic Logic|volume=44|issue=2|pages=267–270|year=1979|doi=10.2307/2273733|jstor=2273733|s2cid=35835482 }}</ref>
# [''x'']''y'' := '''K''' ''y''
# [''x'']''x'' := '''I'''
Line 206 ⟶ 142:
==== Conversion of a lambda term to an equivalent combinatorial term ====
 
For example, we will convert the lambda term ''λx''.''λy''.(''y'' ''x'') to a combinatorial term:
combinatorial term:
 
:''T''[''λx''.''λy''.(''y'' ''x'')]
Line 221 ⟶ 156:
:: = ('''S''' ('''K''' ('''S I''')) ('''S''' ('''K K''') '''I''')) (by 4)
 
If we apply this combinatorial term to any two terms ''x'' and ''y'' (by feeding them in a queue-like fashion into the combinator 'from the right'), it reduces as follows:
reduces as follows:
 
: ('''S''' ('''K''' ('''S''' '''I''')) ('''S''' ('''K''' '''K''') '''I''') x y)
Line 234 ⟶ 168:
:: = (y x)
 
The combinatory representation, ('''S''' ('''K''' ('''S I''')) ('''S''' ('''K K''') '''I''')) is much longer than the representation as a lambda term, ''λx''.''λy''.(y x). This is typical. In general, the ''T''[&nbsp;] construction may expand a lambda term of length ''n'' to a combinatorial term of length [[Big O notation|Θ]](''n''<sup>3</sup>).{{sfn|Lachowski |2018}}
longer than the representation as a lambda term, ''λx''.''λy''.(y x). This is typical. In general, the ''T''[&nbsp;] construction may expand a lambda
term of length ''n'' to a combinatorial term of length
[[Big O notation|Θ]](''n''<sup>3</sup>).<ref>{{cite journal |last1=Lachowski |first1=Łukasz |title=On the Complexity of the Standard Translation of Lambda Calculus into Combinatory Logic |journal=Reports on Mathematical Logic |date=2018 |volume=2018 |issue=53 |pages=19–42 |doi=10.4467/20842589RM.18.002.8835 |url=http://www.ejournals.eu/rml/2018/Number-53/art/12285 |access-date=9 September 2018|doi-access=free }}</ref>
 
==== Explanation of the ''T''[&nbsp;] transformation ====
 
The ''T''[&nbsp;] transformation is motivated by a desire to eliminate abstraction. Two special cases, rules 3 and 4, are trivial: ''λx''.''x'' is clearly equivalent to '''I''', and ''λx''.''E'' is clearly equivalent to ('''K''' ''T''[''E'']) if ''x'' does not appear free in ''E''.
abstraction. Two special cases, rules 3 and 4, are trivial: ''λx''.''x'' is
clearly equivalent to '''I''', and ''λx''.''E'' is clearly equivalent to
('''K''' ''T''[''E'']) if ''x'' does not appear free in ''E''.
 
The first two rules are also simple: Variables convert to themselves,and applications, which are allowed in combinatory terms, are converted to combinators simply by converting the applicand and the argument to combinators.
and applications, which are allowed in combinatory terms, are
converted to combinators simply by converting the applicand and the
argument to combinators.
 
It is rules 5 and 6 that are of interest. Rule 5 simply says that to convert a complex abstraction to a combinator, we must first convert its body to a combinator, and then eliminate the abstraction. Rule 6 actually eliminates the abstraction.
 
''λx''.(''E''₁ ''E''₂) is a function which takes an argument, say ''a'', and substitutes it into the lambda term (''E''₁ ''E''₂) in place of ''x'', yielding (''E''₁ ''E''₂)[''x'' : = ''a'']. But substituting ''a'' into (''E''₁ ''E''₂) in place of ''x'' is just the same as substituting it into both ''E''₁ and ''E''₂, so
substitutes it into the lambda term (''E''₁ ''E''₂) in place of ''x'',
yielding (''E''₁ ''E''₂)[''x'' : = ''a'']. But substituting ''a'' into (''E''₁ ''E''₂) in place of ''x'' is just the same as substituting it into both ''E''₁ and ''E''₂, so
 
: (''E''₁ ''E''₂)[''x'' := ''a''] = (''E''₁[''x'' := ''a''] ''E''₂[''x'' := ''a''])
 
: (''λx''.(''E''₁ ''E''₂) ''a'') = ((''λx''.''E''₁ ''a'') (''λx''.''E''₂ ''a''))
::::: = ('''S''' ''λx''.''E''₁ ''λx''.''E''₂ ''a'')
::::: = (('''S''' ''λx''.''E₁'' ''λx''.''E''₂) ''a'')
 
By extensional equality,
 
: ''λx''.(''E''₁ ''E''₂) = ('''S''' ''λx''.''E''₁ ''λx''.''E''₂)
 
Therefore, to find a combinator equivalent to ''λx''.(''E''₁ ''E''₂), it is sufficient to find a combinator equivalent to ('''S''' ''λx''.''E''₁ ''λx''.''E''₂), and
sufficient to find a combinator equivalent to ('''S''' ''λx''.''E''₁ ''λx''.''E''₂), and
 
: ('''S''' ''T''[''λx''.''E''₁] ''T''[''λx''.''E''₂])
 
evidently fits the bill. ''E''₁ and ''E''₂ each contain strictly fewer applications than (''E''₁ ''E''₂), so the recursion must terminate in a lambda term with no applications at all—either a variable, or a term of the
applications than (''E''₁ ''E''₂), so the recursion must terminate in a lambda
term with no applications at all—either a variable, or a term of the
form ''λx''.''E''.
 
Line 281 ⟶ 201:
==== η-reduction ====
 
The combinators generated by the ''T''[&nbsp;] transformation can be made smaller if we take into account the ''η-reduction'' rule:
smaller if we take into account the ''η-reduction'' rule:
 
: ''T''[''λx''.(''E'' ''x'')] = ''T''[''E''] (if ''x'' is not free in ''E'')
 
''λx''.(''E'' x) is the function which takes an argument, ''x'', and applies the function ''E'' to it; this is extensionally equal to the function ''E'' itself. It is therefore sufficient to convert ''E'' to combinatorial form.
applies the function ''E'' to it; this is extensionally equal to the
function ''E'' itself. It is therefore sufficient to convert ''E'' to
combinatorial form.
 
Taking this simplification into account, the example above becomes:
 
:&nbsp; {{spaces|2}}''T''[''λx''.''λy''.(''y'' ''x'')]
: = ...
: = ('''S''' ('''K''' ('''S I''')) ''T''[''λx''.('''K''' ''x'')])
: = ('''S''' ('''K''' ('''S I''')) '''K''') (by η-reduction)
 
This combinator is equivalent to the earlier, longer one:
 
:&nbsp; {{spaces|2}}('''S''' ('''K''' ('''S I''')) '''K''' ''x y'')
: = ('''K''' ('''S I''') ''x'' ('''K''' ''x'') ''y'')
: = ('''S I''' ('''K''' ''x'') ''y'')
: = ('''I''' ''y'' ('''K''' ''x y''))
: = (''y'' ('''K''' ''x y''))
: = (''y x'')
 
Similarly, the original version of the ''T''[&nbsp;] transformation transformed the identity function ''λf''.''λx''.(''f'' ''x'') into ('''S''' ('''S''' ('''K S''') ('''S''' ('''K K''') '''I''')) ('''K I''')). With the η-reduction rule, ''λf''.''λx''.(''f'' ''x'') is
transformed the identity function ''λf''.''λx''.(''f'' ''x'') into ('''S''' ('''S''' ('''K S''') ('''S''' ('''K K''') '''I''')) ('''K I''')). With the η-reduction rule, ''λf''.''λx''.(''f'' ''x'') is
transformed into '''I'''.
 
Line 315 ⟶ 230:
There are one-point bases from which every combinator can be composed extensionally equal to ''any'' lambda term. The simplest example of such a basis is {'''X'''} where:
 
: '''X''' ≡ ''λx''.((x'''S''')'''K''')
 
It is not difficult to verify that:
: '''X''' ('''X''' ('''X''' '''X''')) =<sup>β</sup> '''K''' and
: '''X''' ('''X''' ('''X''' ('''X''' '''X'''))) =<sup>β</sup> '''S'''.
 
Since {'''K''', '''S'''} is a basis, it follows that {'''X'''} is a basis too. The [[Iota and Jot|Iota]] programming language uses '''X''' as its sole combinator.
Line 325 ⟶ 240:
Another simple example of a one-point basis is:
 
: '''X'''' ≡ ''λx''.(x '''K''' '''S''' '''K''') with
: ('''X'''' '''X'''') '''X'''' =<sup>β</sup> '''K''' and
: '''X'''' ('''X'''' '''X'''') =<sup>β</sup> '''S'''
 
In fact, there exist infinitely many such bases.<ref>{{cite journal sfn| first=Mayer | last=Goldberg | doi=10.1016/j.ipl.2003.12.005 | volume=89 | issue=6 | year=2004 | title=A construction of one-point bases in extended lambda calculi | journal=Information Processing Letters | pages=281–286}}</ref>
 
==== Combinators B, C ====
 
In addition to '''S''' and '''K''', [[Moses Schönfinkel{{harvtxt|Schönfinkel]]'s paper|1924}} included two combinators which are now called '''B''' and '''C''', with the following reductions:
 
: ('''C''' ''f'' ''g'' ''x'') = ((''f'' ''x'') ''g'')
: ('''B''' ''f'' ''g'' ''x'') = (''f'' (''g'' ''x''))
 
He also explains how they in turn can be expressed using only '''S''' and '''K''':
 
: '''B''' = ('''S''' ('''K S''') '''K''')
: '''C''' = ('''S''' ('''S''' ('''K''' ('''S''' ('''K S''') '''K''')) '''S''') ('''K K'''))
 
These combinators are extremely useful when translating predicate logic or lambda calculus into combinator expressions. They were also used by [[Haskell Curry|Curry]], and much later by [[David Turner (computer scientist)|David Turner]], whose name has been associated with their computational use. Using them, we can extend the rules for the transformation as follows:
 
# ''T''[''x''] ⇒ ''x''
# ''T''[(''E₁'' ''E₂'')] ⇒ (''T''[''E₁''] ''T''[''E₂''])
# ''T''[''λx''.''E''] ⇒ ('''K''' ''T''[''E'']) (if ''x'' is not free in ''E'')
# ''T''[''λx''.''x''] ⇒ '''I'''
# ''T''[''λx''.''λy''.''E''] ⇒ ''T''{{!(}}''λx''.''T''{{!(}}''λy''.''E''{{))!}} (if ''x'' is free in ''E'')
# ''T''[''λx''.(''E₁'' ''E₂'')] ⇒ ('''S''' ''T''[''λx''.''E₁''] ''T''[''λx''.''E₂'']) (if ''x'' is free in both ''E₁'' and ''E₂'')
# ''T''[''λx''.(''E₁'' ''E₂'')] ⇒ ('''C''' ''T''[''λx''.''E₁''] ''T''[''E₂'']) (if ''x'' is free in ''E₁'' but not ''E₂'')
# ''T''[''λx''.(''E₁'' ''E₂'')] ⇒ ('''B''' ''T''[''E₁''] ''T''[''λx''.''E₂'']) (if ''x'' is free in ''E₂'' but not ''E₁'')
 
Using '''B''' and '''C''' combinators, the transformation of ''λx''.''λy''.(''y'' ''x'') looks like this:
''λx''.''λy''.(''y'' ''x'') looks like this:
 
:&nbsp;&nbsp; {{spaces|2}}''T''[''λx''.''λy''.(''y'' ''x'')]
: = ''T''{{!(}}''λx''.''T''{{!(}}''λy''.(''y'' ''x''){{))!}}
: = ''T''[''λx''.('''C''' ''T''[''λy''.''y''] ''x'')] (by rule 7)
: = ''T''[''λx''.('''C''' '''I''' ''x'')]
: = ('''C''' '''I''') (η-reduction)
: = <math>\mathbf{C}_{*}</math> (traditional canonical notation : <math>\mathbf{X}_{*} = \mathbf{X I}</math>)
: = <math>\mathbf{I}'</math> (traditional canonical notation: <math>\mathbf{X}' = \mathbf{C X}</math>)
 
And indeed, ('''C''' '''I''' ''x'' ''y'') does reduce to (''y'' ''x''):
 
:&nbsp;&nbsp; {{spaces|2}}('''C''' '''I''' ''x'' ''y'')
: = ('''I''' ''y'' ''x'')
: = (''y'' ''x'')
 
The motivation here is that '''B''' and '''C''' are limited versions of '''S'''. Whereas '''S''' takes a value and substitutes it into both the applicand and its argument before performing the application, '''C''' performs the
Whereas '''S''' takes a value and substitutes it into both the applicand and
its argument before performing the application, '''C''' performs the
substitution only in the applicand, and '''B''' only in the argument.
 
The modern names for the combinators come from [[Haskell Curry]]'s doctoral thesis of 1930 (see [[B, C, K, W System]]). In [[Moses Schönfinkel|Schönfinkel]]'s original paper, what we now call '''S''', '''K''', '''I''', '''B''' and '''C''' were called '''S''', '''C''', '''I''', '''Z''', and '''T''' respectively.
 
The reduction in combinator size that results from the new transformation rules can also be achieved without introducing '''B''' and '''C''', as demonstrated in Section 3.2 of {{harvtxt|Tromp|2008}}.
can also be achieved without introducing '''B''' and '''C''', as demonstrated in Section 3.2 of.
<ref>{{cite book |first=John |last=Tromp |chapter=Binary Lambda Calculus and Combinatory Logic |title=Randomness And Complexity, from Leibniz To Chaitin |editor-first=Cristian S. |editor-last=Calude |publisher=World Scientific Publishing Company |year=2008 |chapter-url=http://tromp.github.io/cl/LC.pdf|archive-url=https://web.archive.org/web/20160304083208/http://tromp.github.io/cl/LC.pdf |archive-date=2016-03-04 }}</ref>
 
===== CL<sub>K</sub> versus CL<sub>I</sub> calculus =====
Line 389 ⟶ 299:
=== Reverse conversion ===
 
The conversion ''L''[&nbsp;] from combinatorial terms to lambda terms is trivial:
trivial:
 
: ''L''['''I'''] = ''λx''.''x''
: ''L''['''K'''] = ''λx''.''λy''.''x''
: ''L''['''C'''] = ''λx''.''λy''.''λz''.(''x'' ''z'' ''y'')
: ''L''['''B'''] = ''λx''.''λy''.''λz''.(''x'' (''y'' ''z''))
: ''L''['''S'''] = ''λx''.''λy''.''λz''.(''x'' ''z'' (''y'' ''z''))
: ''L''[(''E₁'' ''E₂'')] = (''L''[''E₁''] ''L''[''E₂''])
 
Note, however, that this transformation is not the inverse
Line 408 ⟶ 317:
First, the term
 
: '''Ω''' = ('''S''' '''I''' '''I''' ('''S''' '''I''' '''I'''))
 
has no normal form, because it reduces to itself after three steps, as follows:
follows:
 
:{{spaces|2}} ('''S''' '''I''' '''I''' ('''S''' '''I''' '''I'''))
: = ('''I''' ('''S''' '''I''' '''I''') ('''I''' ('''S''' '''I''' '''I''')))
: = ('''S''' '''I''' '''I''' ('''I''' ('''S''' '''I''' '''I''')))
: = ('''S''' '''I''' '''I''' ('''S''' '''I''' '''I'''))
and clearly no other reduction order can make the expression shorter.
 
Now, suppose '''N''' were a combinator for detecting normal forms, such that
such that
 
:<math>(\mathbf{N} \ x) = \begin{cases} \mathbf{T}, \text{ if } x \text{ has a normal form} \\
Line 428 ⟶ 335:
Now let
 
: ''Z'' = ('''C''' ('''C''' ('''B''' '''N''' ('''S''' '''I''' '''I''')) '''Ω''') '''I''')
 
now consider the term ('''S''' '''I''' '''I''' ''Z''). Does ('''S''' '''I''' '''I''' ''Z'') have a normal
form? It does if and only if the following do also:
 
:{{spaces|2}} ('''S''' '''I''' '''I''' ''Z'')
: = ('''I''' ''Z'' ('''I''' ''Z''))
: = (''Z'' ('''I''' ''Z''))
: = (''Z'' ''Z'')
: = ('''C''' ('''C''' ('''B''' '''N''' ('''S''' '''I''' '''I''')) '''Ω''') '''I''' ''Z'') (definition of ''Z'')
: = ('''C''' ('''B''' '''N''' ('''S''' '''I''' '''I''')) '''Ω''' ''Z'' '''I''')
: = ('''B''' '''N''' ('''S''' '''I''' '''I''') ''Z'' '''Ω''' '''I''')
: = ('''N''' ('''S''' '''I''' '''I''' ''Z'') '''Ω''' '''I''')
Now we need to apply '''N''' to ('''S''' '''I''' '''I''' ''Z'').
Either ('''S''' '''I''' '''I''' ''Z'') has a normal form, or it does not. If it ''does'' have a normal form, then the foregoing reduces as follows:
have a normal form, then the foregoing reduces as follows:
 
:{{spaces|2}} ('''N''' ('''S''' '''I''' '''I''' ''Z'') '''Ω''' '''I''')
: = ('''K''' '''Ω''' '''I''') (definition of '''N''')
: = '''Ω'''
but '''Ω''' does ''not'' have a normal form, so we have a contradiction. But
if ('''S''' '''I''' '''I''' ''Z'') does ''not'' have a normal form, the foregoing reduces as follows:
follows:
 
:{{spaces|2}} ('''N''' ('''S''' '''I''' '''I''' ''Z'') '''Ω''' '''I''')
: = ('''K''' '''I''' '''Ω''' '''I''') (definition of '''N''')
: = ('''I''' '''I''')
: = '''I'''
which means that the normal form of ('''S''' '''I''' '''I''' ''Z'') is simply '''I''', another
contradiction. Therefore, the hypothetical normal-form combinator '''N''' cannot exist.
cannot exist.
 
The combinatory logic analogue of [[Rice's theorem]] says that there is no complete nontrivial predicate. A ''predicate'' is a combinator that, when applied, returns either '''T''' or '''F'''. A predicate '''N''' is ''nontrivial'' if there are two arguments ''A'' and ''B'' such that '''N''' ''A'' = '''T''' and '''N''' ''B'' = '''F'''. A combinator '''N''' is ''complete'' if '''N'''''M'' has a normal form for every argument ''M''. The analogue of Rice's theorem then says that every complete predicate is trivial. The proof of this theorem is rather simple.
{{math proof
| proof = By reductio ad absurdum. Suppose there is a complete non trivial predicate, say '''N'''. Because '''N''' is supposed to be non trivial there are combinators ''A'' and ''B'' such that
Line 492 ⟶ 396:
David Turner used his combinators to implement the [[SASL programming language]].
 
[[Kenneth E. Iverson]] used primitives based on Curry's combinators in his [[J programming language]], a successor to [[APL (programming language)|APL]]. This enabled what Iverson called [[tacit programming]], that is, programming in functional expressions containing no variables, along with powerful tools for working with such programs. It turns out that tacit programming is possible in any APL-like language with user-defined operators.<ref>{{cite book sfn|first=Edward |last=Cherlin |title=Proceedings of the international conference on APL '91 - APL '91 |chapter=Pure functions in APL and J |pages=88–93 |year=1991 |doi=10.1145/114054.114065|isbn=0897914414 |s2cid=25802202 }}</ref>
<!--
(Discuss strict vs. [[lazy evaluation]] semantics. Note implications of
graph reduction implementation for lazy evaluation. Point out
efficiency problem in lazy semantics: Repeated evaluation of the same
expression, in, e.g. (square COMPLICATED) => (* COMPLICATED
COMPLICATED), normally avoided by eager evaluation and call-by-value.
Discuss benefit of graph reduction in this case: when (square
COMPLICATED) is evaluated, the representation of COMPLICATED can be
shared by both branches of the resulting graph for (* COMPLICATED
COMPLICATED), and evaluated only once.)
-->
<!-- Work in [[combinator library]] somehow. -->
 
=== Logic ===
Line 534 ⟶ 426:
 
== References ==
{{reflist|2}}
 
==Further readingLiterature==
* {{cite book| last=Barendregt|first=Hendrik Pieter|author-link=Henk Barendregt|year=1984|title=The Lambda Calculus, Its Syntax and Semantics. Studies in Logic and the Foundations of Mathematics|volume=103| publisher=[[North-Holland Publishing Company|North Holland]] |isbn=0-444-87508-5}}
*{{cite book|first=Edward |last=Cherlin |title=Proceedings of the international conference on APL '91 - APL '91 |chapter=Pure functions in APL and J |pages=88–93 |year=1991 |doi=10.1145/114054.114065|isbn=0897914414 |s2cid=25802202 }}
* {{cite book| last1=Curry|first1=Haskell B.|author-link1=Haskell Curry|last2=Feys|first2=Robert|author-link2=Robert Feys|title=Combinatory Logic|volume=I|year=1958|publisher=North Holland|location=Amsterdam|isbn=0-7204-2208-6}}
*{{cite journal|last=Curry|first=Haskell Brooks|title=Grundlagen der Kombinatorischen Logik|journal=American Journal of Mathematics|year=1930|volume=52|issue=3|pages=509–536|author-link=Haskell Curry|trans-title=Foundations of combinatorial logic|publisher=The Johns Hopkins University Press|language=de|doi=10.2307/2370619|jstor=2370619}}
* {{cite book| last1=Curry|first1=Haskell B.|author-link1=Haskell Curry|first2=J. Roger|last2=Hindley|author-link2=J. Roger Hindley|first3=Jonathan P.|last3=Seldin|title=Combinatory Logic|volume=II|year=1972| publisher=North Holland |location=Amsterdam | isbn=0-7204-2208-6}}
* {{cite book| last1=Field Curry|first1=Anthony J.Haskell Brooks|first2author-link1=Peter G.Haskell Curry|last2=Harrison Feys|first2=Robert|author-link2=Peter G. HarrisonRobert Feys|yeartitle=1998Combinatory Logic|titlevolume=Functional Programming I|urlyear=https://archive.org/details/functionalprogra0000fiel 1958|url-accesspublisher=registrationNorth Holland|publisherlocation=Addison-Wesley Amsterdam|isbn=0-2017204-192492208-76}}
* {{citationcite book| last1=HindleyCurry|first1=J.Haskell RogerBrooks|author-link1=Haskell Curry|first2=J. Roger Hindley|last2=MeredithHindley|first2author-link2=David|title=PrincipalJ. type-schemesRoger and condensed detachmentHindley|urlfirst3=http://projecteuclid.org/euclidJonathan P.jsl/1183743187|mrlast3=1043546Seldin|journaltitle=[[Journal of SymbolicCombinatory Logic]]|volume = 55|issue=1|pages=90–105II|year=19901972|doi publisher=10.2307/2274956North Holland |jstorlocation=2274956Amsterdam |s2cid=6930576 isbn=0-7204-2208-6}}
* {{cite book| |last1=HindleyField |first1=Anthony J. R|first2=Peter G.|last2=Harrison |author-link1link2=JPeter G. Roger HindleyHarrison |last2year=Seldin1998 |first2title=J.Functional P. |year=2008Programming |url=httphttps://www.cambridgearchive.org/cataloguedetails/catalogue.asp?isbnfunctionalprogra0000fiel |url-access=9780521898850registration |titlepublisher=λAddison-calculus and Combinators: An IntroductionWesley |publisherisbn=[[Cambridge University Press]]0-201-19249-7}}
*{{cite journal | first=Mayer | last=Goldberg | doi=10.1016/j.ipl.2003.12.005 | volume=89 | issue=6 | year=2004 | title=A construction of one-point bases in extended lambda calculi | journal=Information Processing Letters | pages=281–286}}
*{{cite journal| last1=Hindley|first1=J. Roger|author-link1=J. Roger Hindley|last2=Meredith|first2=David|title=Principal type-schemes and condensed detachment|url=http://projecteuclid.org/euclid.jsl/1183743187|mr=1043546|journal=[[Journal of Symbolic Logic]]|volume = 55|issue=1|pages=90–105|year=1990|doi=10.2307/2274956|jstor=2274956|s2cid=6930576}}
*{{cite book |last1=Hindley |first1=J. R. |author-link1=J. Roger Hindley |last2=Seldin |first2=J. P. |year=2008 |url=http://www.cambridge.org/catalogue/catalogue.asp?isbn=9780521898850 |title=λ-calculus and Combinators: An Introduction |publisher=[[Cambridge University Press]]}}
*{{cite journal |last=Lachowski |first=Łukasz |title=On the Complexity of the Standard Translation of Lambda Calculus into Combinatory Logic |journal=Reports on Mathematical Logic |date=2018 |volume=2018 |issue=53 |pages=19–42 |doi=10.4467/20842589RM.18.002.8835 |url=http://www.ejournals.eu/rml/2018/Number-53/art/12285 |access-date=9 September 2018|doi-access=free}}
* {{cite book |last=Paulson |first=Lawrence C. |author-link=Lawrence Paulson |year=1995 |url=http://www.cl.cam.ac.uk/Teaching/Lectures/founds-fp/Founds-FP.ps.gz |title=Foundations of Functional Programming |publisher=University of Cambridge}}
* <span id="Quine 1960">{{cite journal |author-link=Willard Van Orman Quine |last=Quine |first=W. V. |year=1960 |title=Variables explained away |journal=Proceedings of the American Philosophical Society |volume=104 |issue=3 |pages=343–347 |jstor=985250}} |quote=Reprinted as Chapter 23 of {{harvtxt|Quine's ''Selected Logic Papers'' (1966), pp.&nbsp;227–235</span>|1996}}}}
*{{cite book |author-link=Willard Van Orman Quine |last=Quine |first=W. V.|year=1996|orig-date=1960|chapter=Variables explained away|title=Selected Logic Papers|publisher=[[Harvard University Press]]|location=Cambridge, Mass.|pages=227–235|isbn=9780674798373|edition=Enl. ed., 2. print}}
* [[Moses Schönfinkel|Schönfinkel, Moses]], 1924, "[http://www.cip.ifi.lmu.de/~langeh/test/1924%20-%20Schoenfinkel%20-%20Ueber%20die%20Bausteine%20der%20mathematischen%20Logik.pdf Über die Bausteine der mathematischen Logik]," translated as "On the Building Blocks of Mathematical Logic" in ''From Frege to Gödel: a source book in mathematical logic, 1879–1931'', [[Jean van Heijenoort]], ed. [[Harvard University Press]], 1967. {{ISBN|0-674-32449-8}}. The article that founded combinatory logic.
*{{cite journal |first=Moses |last=Schönfinkel |author-link=Moses Schönfinkel |year=1924 |url=http://www.cip.ifi.lmu.de/~langeh/test/1924%20-%20Schoenfinkel%20-%20Ueber%20die%20Bausteine%20der%20mathematischen%20Logik.pdf |title=Über die Bausteine der mathematischen Logik |journal=Mathematische Annalen |volume=92 |issue=3–4 |pages=305–316 |doi=10.1007/bf01448013|s2cid=118507515|language=de|quote=The article that founded combinatory logic. English translation: {{harvtxt|Schönfinkel|1967}}}}
*{{cite book |first=Moses|last=Schönfinkel|author-link=Moses Schönfinkel|orig-year=1924|translator-first=Stefan|translator-last=Bauer-Mengelberg|title=Über die Bausteine der mathematischen Logik|trans-title=On the building blocks of mathematical logic|editor-first= Jean|editor-last=Van Heijenoort|editor-link=Jean van Heijenoort|year=1967|series=From Frege to Gödel: A Source Book in Mathematical Logic, 1879-1931|publisher=[[Harvard University Press]]| location=Cambridge, MA, USA|language=en|pages=355-366|isbn=978-0674324497|oclc=503886453}}
*{{cite web|last=Seldin|first=Jonathan P.|title=The Logic of Curry and Church|date=3 March 2008|url=http://people.uleth.ca/%7Ejonathan.seldin/CCL.pdf|access-date=17 September 2023}}
* [[Raymond Smullyan|Smullyan, Raymond]], 1985. ''[[To Mock a Mockingbird]]''. Knopf. {{ISBN|0-394-53491-3}}. A gentle introduction to combinatory logic, presented as a series of recreational puzzles using bird watching metaphors.
* ______, 1994. ''Diagonalization and Self-Reference''. [[Oxford University Press]]. Chapters 17–20 are a more formal introduction to combinatory logic, with a special emphasis on fixed point results.
* Sørensen, Morten Heine B. and Paweł Urzyczyn, 1999. ''[https://web.archive.org/web/20051016213140/http://folli.loria.fr/cds/1999/library/pdf/curry-howard.pdf Lectures on the Curry–Howard Isomorphism]''. [[University of Copenhagen]] and [[University of Warsaw]], 1999.
*{{cite book |first=John |last=Tromp |chapter=Binary Lambda Calculus and Combinatory Logic |title=Randomness And Complexity, from Leibniz To Chaitin |editor-first=Cristian S. |editor-last=Calude |publisher=World Scientific Publishing Company |year=2008 |chapter-url=http://tromp.github.io/cl/LC.pdf|archive-url=https://web.archive.org/web/20160304083208/http://tromp.github.io/cl/LC.pdf |archive-date=2016-03-04}}
*{{cite journal|last=Turner|first=David A.|author-link=David Turner (computer scientist)|title=Another Algorithm for Bracket Abstraction|journal=The Journal of Symbolic Logic|volume=44|issue=2|pages=267–270|year=1979|doi=10.2307/2273733|jstor=2273733|s2cid=35835482}}
* {{cite book |last=Wolfengagen |first=V. E. |url=https://archive.org/details/CLP-2003_780 |title=Combinatory logic in programming: Computations with objects through examples and exercises |edition=2nd |location=Moscow |publisher="Center JurInfoR" Ltd. |year=2003 |isbn=5-89158-101-9}}
* {{cite book| last=Wolfram | first=Stephen | authorlink=Stephen Wolfram | url=https://www.wolfram-media.com/products/combinators-a-centennial-view.html |title= Combinators: A Centennial View | publisher=[[Wolfram Media]] | year=2021 | isbn=978-1-57955-043-1 }} e{{ISBN|978-1-57955-044-8}}. A celebration of the development of combinators, a hundred years after they were introduced by [[Moses Schönfinkel]] in 1920.