The SKI combinator calculus is a
combinatory logic system and a
computational system. It can be thought of as a computer programming language, though it is not convenient for writing software. Instead, it is important in the mathematical theory of
algorithm
In mathematics and computer science, an algorithm () is a finite sequence of Rigour#Mathematics, mathematically rigorous instructions, typically used to solve a class of specific Computational problem, problems or to perform a computation. Algo ...
s because it is an extremely simple
Turing complete language. It can be likened to a reduced version of the untyped
lambda calculus
In mathematical logic, the lambda calculus (also written as ''λ''-calculus) is a formal system for expressing computability, computation based on function Abstraction (computer science), abstraction and function application, application using var ...
. It was introduced by
Moses Schönfinkel and
Haskell Curry.
All operations in lambda calculus can be encoded via
abstraction elimination into the SKI calculus as
binary tree
In computer science, a binary tree is a tree data structure in which each node has at most two children, referred to as the ''left child'' and the ''right child''. That is, it is a ''k''-ary tree with . A recursive definition using set theor ...
s whose leaves are one of the three symbols S, K, and I (called ''combinators'').
Notation
Although the most formal representation of the objects in this system requires binary trees, for simpler typesetting they are often represented as parenthesized expressions, as a shorthand for the tree they represent. Any subtrees may be parenthesized, but often only the right-side subtrees are parenthesized, with left associativity implied for any unparenthesized applications. For example, ISK means ((IS)K). Using this notation, a tree whose left subtree is the tree KS and whose right subtree is the tree SK can be written as KS(SK). If more explicitness is desired, the implied parentheses can be included as well: ((KS)(SK)).
Informal description
Informally, and using programming language jargon, a tree (''xy'') can be thought of as a function ''x'' applied to an argument ''y''. When evaluated (''i.e.'', when the function is "applied" to the argument), the tree "returns a value", ''i.e.'', transforms into another tree. The "function", "argument" and the "value" are either combinators or binary trees. If they are binary trees, they may be thought of as functions too, if needed.
The evaluation operation is defined as follows:
(''x'', ''y'', and ''z'' represent expressions made from the functions S, K, and I, and set values):
I returns its argument:
:I''x'' = ''x''
K, when applied to any argument ''x'', yields a one-argument constant function K''x'', which, when applied to any argument ''y'', returns ''x'':
:K''xy'' = ''x''
S is a substitution operator. It takes three arguments and then returns the first argument applied to the third, which is then applied to the result of the second argument applied to the third. More clearly:
:S''xyz'' = ''xz''(''yz'')
Example computation: SKSK evaluates to KK(SK) by the S-rule. Then if we evaluate KK(SK), we get K by the K-rule. As no further rule can be applied, the computation halts here.
For all trees ''x'' and all trees ''y'', SK''xy'' will always evaluate to ''y'' in two steps, K''y''(''xy'') = ''y'', so the ultimate result of evaluating SK''xy'' will always equal the result of evaluating ''y''. We say that SK''x'' and I are "functionally equivalent" for any ''x'' because they always yield the same result when applied to any ''y''.
From these definitions it can be shown that SKI calculus is not the minimum system that can fully perform the computations of lambda calculus, as all occurrences of I in any expression can be replaced by (SKK) or (SKS) or (SK ''x'') for any ''x'', and the resulting expression will yield the same result. So the "I" is merely
syntactic sugar. Since I is optional, the system is also referred as SK calculus or SK combinator calculus.
It is possible to define a complete system using only one (improper) combinator. An example is Chris Barker's
iota
Iota (; uppercase Ι, lowercase ι; ) is the ninth letter of the Greek alphabet. It was derived from the Phoenician letter Yodh. Letters that arose from this letter include the Latin I and J, the Cyrillic І (І, і), Yi (Ї, ї), and J ...
combinator, which can be expressed in terms of S and K as follows:
: ι''x'' = ''x''SK = S(λ''x''.''x''S)(λ''x''.K) = S(S(λx.x)(λx.S))(KK) = S(SI(KS))(KK)
It is possible to reconstruct S, K, and I from the iota combinator. Applying ι to itself gives ιι = ιSK = SSKK = SK(KK) which is functionally equivalent to I. K can be constructed by applying ι twice to I (which is equivalent to application of ι to itself): ι(ι(ιι)) = ι(ιιSK) = ι(ISK) = ι(SK) = SKSK = K. Applying ι one more time gives ι(ι(ι(ιι))) = ιK = KSK = S.
The simplest possible term forming a basis is X = λf.f λxyz.x z (y z) λxyz.x, which satisfies X X = K, and X (X X) = S.
Formal definition
The terms and derivations in this system can also be more formally defined:
Terms:
The set ''T'' of terms is defined recursively by the following rules.
# S, K, and I are terms.
# If τ
1 and τ
2 are terms, then (τ
1τ
2) is a term.
# Nothing is a term if not required to be so by the first two rules.
Derivations:
A derivation is a finite sequence of terms defined recursively by the following rules (where α and ι are words over the alphabet while β, γ and δ are terms):
# If Δ is a derivation ending in an expression of the form α(Iβ)ι, then Δ followed by the term αβι is a derivation.
# If Δ is a derivation ending in an expression of the form α((Kβ)γ)ι, then Δ followed by the term αβι is a derivation.
# If Δ is a derivation ending in an expression of the form α(((Sβ)γ)δ)ι, then Δ followed by the term α((βδ)(γδ))ι is a derivation.
Assuming a sequence is a valid derivation to begin with, it can be extended using these rules. All derivations of length 1 are valid derivations.
Converting lambda calculus expressions into SKI combinator calculus expressions
An expression in the lambda calculus can be converted into an SKI combinator calculus expression in accordance with the following rules:
# λ''x''. ''x'' = I
# λ''x''. c = Kc (provided that c does not depend on ''x'')
# λ''x''. ''f'' ''x'' = ''f''
# λ''x''. ''y'' ''z'' = S(λ''x''.''y'')(λ''x''.''z'')
SKI expressions
Self-application and recursion
SII is an expression that takes an argument and applies that argument to itself:
: SIIα = Iα(Iα) = αα
This is also known as U combinator, U''x'' = ''xx''. One interesting property of it is that its self-application is irreducible:
: SII(SII) = I(SII)(I(SII)) = SII(I(SII)) = SII(SII)
Or, using the equation as its definition directly, we immediately get U U = U U.
Another thing is that it allows one to write a function that applies one thing to the self application of another thing:
: (S(Kα)(SII))β = Kαβ(SIIβ) = α(Iβ(Iβ)) = α(ββ)
or it can be seen as defining yet another combinator directly, H''xy'' = ''x''(''yy'').
This function can be used to achieve
recursion
Recursion occurs when the definition of a concept or process depends on a simpler or previous version of itself. Recursion is used in a variety of disciplines ranging from linguistics to logic. The most common application of recursion is in m ...
. If β is the function that applies α to the self application of something else,
: β = Hα = S(Kα)(SII)
then the self-application of this β is the fixed point of that α:
: SIIβ = ββ = α(ββ) = α(α(ββ)) =
Or, directly again from the derived definition, Hα(Hα) = α(Hα(Hα)).
If α expresses a "computational step" computed by αρν for some ρ and ν, that assumes ρν' expresses "the rest of the computation" (for some ν' that α will "compute" from ν), then its fixed point ββ expresses the whole recursive computation, since using ''the same function'' ββ for the "rest of computation" call (with ββν = α(ββ)ν) is the very definition of recursion: ρν' = ββν' = α(ββ)ν' = ... . α will have to employ some kind of conditional to stop at some "base case" and not make the recursive call then, to avoid divergence.
This can be formalized, with
: β = Hα = S(Kα)(SII) = S(KS)Kα(SII) = S(S(KS)K)(K(SII)) α
as
: Yα = SIIβ = SII(Hα) = S(K(SII))H α = S(K(SII))(S(S(KS)K)(K(SII))) α
which gives us
one possible encoding of the Y combinator. A shorter variation replaces its two leading subterms with just SSI, since Hα(Hα) = SHHα = SSIHα.
This becomes much shorter with the use of the
B,C,W combinators, as
the equivalent
The Equivalent was a sum negotiated at £398,085 10s. 0d. () paid to Scotland by the English Government under the terms of the Acts of Union 1707. Proposals for it first emerged in the course of abortive Union negotiations in 1702 to 1703.
The E ...
: Yα = S(KU)(SB(KU))α = U(BαU) = BU(CBU)α = SSI(CBU)α
And with a pseudo-
Haskell
Haskell () is a general-purpose, statically typed, purely functional programming language with type inference and lazy evaluation. Designed for teaching, research, and industrial applications, Haskell pioneered several programming language ...
syntax it becomes the exceptionally short Y = U . (. U).
Following this approach, other fixpoint combinator definitions are possible. Thus,
* This Y, by
Haskell Curry:
: H''gx'' = ''g''(''xx'') ; Y''g'' = H''g''(H''g'') ; Y = SSI(SB(KU)) = SSI(S(S(KS)K)(K(SII)))
* Turing's Θ:
: H''hg'' = ''g''(''hhg'') ; Θ''g'' = HH''g'' ; Θ = U(B(SI)U) = SII(S(K(SI))(SII))
* Y' (with SK-encoding by
John Tromp):
: H''gh'' = ''g''(''hgh'') ; Yg'' = H''g''H ; Y' = WC(SB(C(WC))) = SSK(S(K(SS(S(SSK))))K)
* Θ₄ by R.Statman:
: H''gyz'' = ''g''(''yyz'') ; Θ₄''g'' = H''g''(H''g'')(H''g'') ; Θ₄ = B(WW)(BW(BBB))
* or in general,
: H''something'' = ''g''(''hsomething'') ; Y
H ''g'' = H_____H__ ''g''
: (where anything goes instead of "_") or any other intermediary H combinator's definition, with its correspondent Y definition to jump-start it correctly. In particular,
: L''abcdefghijklmnopqstuvwxyzr'' = ''r''(''thisisafixedpointcombinator'') ; Y = LLLLLLLLLLLLLLLLLLLLLLLLLL
In a
strict programming language the
Y combinator
Y Combinator, LLC (YC) is an American technology startup accelerator and venture capital firm launched in March 2005 which has been used to launch more than 5,000 companies. The accelerator program started in Boston and Mountain View, Californi ...
will expand until
stack overflow
In software, a stack overflow occurs if the call stack pointer exceeds the stack bound. The call stack may consist of a limited amount of address space, often determined at the start of the program. The size of the call stack depends on many fa ...
, or never halt in case of
tail call optimization.
The
Z combinator will work in
strict languages (also called eager languages, where applicative evaluation order is applied).
:
The reversal expression
S(K(SI))K reverses the two terms following it:
: S(K(SI))Kαβ →
: K(SI)α(Kα)β →
: SI(Kα)β →
: Iβ(Kαβ) →
: Iβα →
: βα
It is thus equivalent to CI. And in general, S(K(S''f''))K is equivalent to C''f'', for any ''f''.
Boolean logic
SKI combinator calculus can also implement
Boolean logic
In mathematics and mathematical logic, Boolean algebra is a branch of algebra. It differs from elementary algebra in two ways. First, the values of the variable (mathematics), variables are the truth values ''true'' and ''false'', usually denot ...
in the form of an ''if-then-else'' structure. An ''if-then-else'' structure consists of a Boolean expression that is either true (T) or false (F) and two arguments, such that:
: T''xy'' = ''x''
and
: F''xy'' = ''y''
The key is in defining the two Boolean expressions. The first works just like one of our basic combinators:
: T = K
: K''xy'' = ''x''
The second is also fairly simple:
: F = SK
: SK''xy'' = K''y(xy)'' = y
Once true and false are defined, all Boolean logic can be implemented in terms of ''if-then-else'' structures.
Boolean NOT (which returns the opposite of a given Boolean) works the same as the ''if-then-else'' structure, with F and T as the second and third values, so it can be implemented as a postfix operation:
: NOT = λb.b (F)(T) = λb.b (SK)(K)
If this is put in an ''if-then-else'' structure, it can be shown that this has the expected result
: (T)NOT = T(F)(T) = F
: (F)NOT = F(F)(T) = T
Boolean OR (which returns T if either of the two Boolean values surrounding it is T) works the same as an ''if-then-else'' structure with T as the second value, so it can be implemented as an infix operation:
: OR = T = K
If this is put in an ''if-then-else'' structure, it can be shown that this has the expected result:
: (T)OR(T) = T(T)(T) = T
: (T)OR(F) = T(T)(F) = T
: (F)OR(T) = F(T)(T) = T
: (F)OR(F) = F(T)(F) = F
Boolean AND (which returns T if both of the two Boolean values surrounding it are T) works the same as an ''if-then-else'' structure with F as the third value, so it can be implemented as a postfix operation:
: AND = F = SK
If this is put in an ''if-then-else'' structure, it can be shown that this has the expected result:
: (T)(T)AND = T(T)(F) = T
: (T)(F)AND = T(F)(F) = F
: (F)(T)AND = F(T)(F) = F
: (F)(F)AND = F(F)(F) = F
Because this defines T, F, NOT (as a postfix operator), OR (as an infix operator), and AND (as a postfix operator) in terms of SKI notation, this proves that the SKI system can fully express Boolean logic.
As the SKI calculus is
complete, it is also possible to express NOT, OR and AND as prefix operators:
: NOT = S(SI(KF))(KT) (as S(SI(KF))(KT)''x'' = SI(KF)''x''(KT''x'') = I''x''(KF''x'')T = ''x''FT)
: OR = SI(KT) (as SI(KT)''xy'' = I''x''(KT''x'')''y'' = ''x''T''y'')
: AND = SS(K(KF)) (as SS(K(KF))''xy'' = S''x''(K(KF)''x'')''y'' = ''xy''(KF''y'') = ''xy''F)
Connection to intuitionistic logic
The combinators K and S correspond to two well-known axioms of
sentential logic:
:,
:.
Function application corresponds to the rule
modus ponens
In propositional logic, (; MP), also known as (), implication elimination, or affirming the antecedent, is a deductive argument form and rule of inference. It can be summarized as "''P'' implies ''Q.'' ''P'' is true. Therefore, ''Q'' must ...
:
:: from and , infer .
The axioms AK and AS, and the rule MP are complete for the implicational fragment of
intuitionistic logic. In order for combinatory logic to have as a model:
*The
implicational fragment of
classical logic
Classical logic (or standard logic) or Frege–Russell logic is the intensively studied and most widely used class of deductive logic. Classical logic has had much influence on analytic philosophy.
Characteristics
Each logical system in this c ...
, would require the combinatory analog to the
law of excluded middle
In logic, the law of excluded middle or the principle of excluded middle states that for every proposition, either this proposition or its negation is true. It is one of the three laws of thought, along with the law of noncontradiction and t ...
, ''i.e.'',
Peirce's law
In logic, Peirce's law is named after the philosopher and logician Charles Sanders Peirce. It was taken as an Axiom#Mathematics, axiom in his first axiomatisation of propositional logic. It can be thought of as the law of excluded middle written ...
;
*
Complete classical logic, would require the combinatory analog to the sentential axiom .
This connection between the types of combinators and the corresponding logical axioms is an instance of the
Curry–Howard isomorphism.
Examples of reduction
There may be multiple ways to do a reduction. All are equivalent, as long as you don't break order of operations
*
**
**
*
**
**
*
See also
*
Combinatory logic
*
B, C, K, W system
*
Fixed point combinator
*
Lambda calculus
In mathematical logic, the lambda calculus (also written as ''λ''-calculus) is a formal system for expressing computability, computation based on function Abstraction (computer science), abstraction and function application, application using var ...
*
Functional programming
In computer science, functional programming is a programming paradigm where programs are constructed by Function application, applying and Function composition (computer science), composing Function (computer science), functions. It is a declarat ...
*
Unlambda programming language
* The
Iota and Jot programming languages, designed to be even simpler than SKI.
* ''
To Mock a Mockingbird''
References
* A gentle introduction to combinatory logic, presented as a series of recreational puzzles using bird watching metaphors.
* are a more formal introduction to combinatory logic, with a special emphasis on fixed point results.
{{refend
External links
* O'Donnell, Mike
The SKI Combinator Calculus as a Universal System.
* Keenan, David C. (2001)
* Rathman, Chris,
*
A Calculus of Mobile Processes, Part I(PostScript) (by Milner, Parrow, and Walker) shows a scheme for ''combinator
graph reduction'' for the SKI calculus in pages 25–28.
* th
Nock programming languagemay be seen as an assembly language based on SK combinator calculus in the same way that traditional assembly language is based on Turing machines. Nock instruction 2 (the "Nock operator") is the S combinator and Nock instruction 1 is the K combinator. The other primitive instructions in Nock (instructions 0,3,4,5, and the pseudo-instruction "implicit cons") are not necessary for universal computation, but make programming more convenient by providing facilities for dealing with binary tree data structures and arithmetic; Nock also provides 5 more instructions (6,7,8,9,10) that could have been built out of these primitives.
Lambda calculus
Combinatory logic