|
Combinative logic occurs as notation introduced by Moses Schönfinkel and Haskell Curry to eliminate the want for variables in mathematical logic. It has sir thomas more recently been utilized inside computing as a theoretical model of computation & as well as a basis for the project of functional programing language.
Combinatory logic in mathematics
Combinative logic was designed as a elementary 'pre-logic' which would clarify a meaning of variables within logical notation, & indeed eliminate a require for the babies.
Understand Curry, 1958-72.
Combinatory logic in computing
Around computing, combinative logic is utilized as a simplified model of computation, used
within computability theory (the learn of what may be computed) & proof theory (the learn of what may be mathematically proven.) The theory, despite its simplicity, captures several essential features of the nature
of computation.
Combinative logic may be scanned at as a variation of the lambda calculus, in which lambdthe expressions (utilized to provide functional abstraction) come replaced by a limited placed of combinators, primitive functions which contain there is no free variables. These are easily to transform lambda expressions into combinator expressions, & since combinator reduction is tremendously simpler than lambda reduction, it hwhen been utilized as a basis for the implementation of a bit of non-strict functional programming languages in software package & hardware.
It can too exist as surfed at around a total of more manners, by having numbers of early papers showing the equivalence of various combinators to various logic axioms [Hindley and Meredith, 1990].
Summary of the lambda calculus
For complete details just about a lambda calculus, see a article
under it head. You may summarize on this text. A lambda calculus is
caring using objects known as lambda-terms, which are then strings of
symbols of one of a below forms:
v
λv.E1
(E1 E2)
in which v occurs as variable title drawn from either the predefined infinite placed of
variable list, & E1 & E2 come lambda-terms. Terms of the
form λv.E1 come known as abstractions. A variable v is
known as a formal parameter of the abstraction, and E1 is the
body of a abstraction.
A term λv.E1 is a work which, applied to an
argument, binds a formal parameter five to the argument and then
computes a resultant value of E1---that is, it is restored E1,
by having each occurrence of v replaced per argument.
Terms of the form (E1 E2) come known as applications.
Applications model work invocation or even execution: a function
delineate by E1 is to become invoked, sustaining E2 when its argument,
& a symptom is computed. Whenever E1 (periodically known as the
applicand) is an abstraction, a term can be reduced: E2,
a argument, can be substituted into a body of E1 in situ of
a formal parameter of E1, & a effect occurs as recently lambda term
which is same to the old a single. Whenever the lambda term contains no
subterms of the form (λv.E1 E2) so it just can't become reduced, & is
said to exist as within normal form.
A expression E[v := a] is a symptom of ingesting a term E & replacing whole loose occurrences of v by having a. So i write
By convention, you choose (the b 100 d ... z) when short for (...(((the b) one hundred) d) ... z). (we.e., application is left associative.)
A motivation for this definition of reduction is that it captures
a essential behavior of 100% mathematical functions. E.g.,
assume the work that computes a square of a total. I personally might
write
(Applying "*" to imply multiplication.) x on this text is the formal parameter of the function. To evaluate the square for a particular
argument, say Trio, i insert it into a definition in situ of the
formal parameter:
To evaluate a consequent expression 3*3, i would stand to resort to
my noesis of multiplication & a total Ternion. Since any
computation is only the composition of the evaluation of suitable
functions in suitable primitive arguments, this elementary substitution
principle suffices to capture a essential mechanism of computation.
What is more, in the lambda calculus, notions like 'Deuce-ace' & '*' can be
delineate forswearing any require for externally defined primitive
operators or even constants. These are conceivable to identify terms in the
lambda calculus, which, whilst appropriately interpreted, behave rather the
total Ternary & rather a multiplication operator.
A lambda calculus is known to become computationally same around power to
numbers of more plausible system for computation (including Turing machines); that is, any calculation that can be accomplished in any
one more system may be expressed in the lambda calculus, and
the other way around. Based on data from a Church-Turing thesis, both models
could express any imaginable computation.
These are mayhap surprising that lambda-calculus might represent any
conceivable computation applying lone a elementary notions of function
abstraction & application according to elementary textual substitution of
terms for variables. However possibly other remarkable is that abstraction is
non potentially involved. Combinative logic occurs as model of computation
same to the lambda calculus, however while forgoing abstraction.
Combinatory calculi
Since abstraction is the single way to manufacture functions in the
lambda calculus, something must replenish it in the combinatory
calculus. Instead of abstraction, combinative calculus will bring a
limited placed of primitive functions away from which more functions may be
built.
Combinatory terms
a combinative term has one of the as a result forms:
v
P
(E1 E2)
in which v occurs as variable, P is one of a primitive functions, & E1 & E2 come combinative terms. A primitive functions themselves come combinators, or even functions that contain there are no free variables.
Examples of combinators
the simplest lesson of a combinator is We, a identity
combinator, defined by
for tons terms x. A second elementary combinator is One thousand, which
manufactures constant functions: (One thousand x) is the work which,
for any argument, comes back x, then i say
for a lot terms x & y. Or even, as a consequence a equivalent convention for
multiple application when in the lambda-calculus,
The third combinator is S, which occurs as generalized version of
application:
S applies x to y fallowing number 1 subbing z into
both of the two.
Given S & K, I personally itself is unneeded, since it can
become built from either a more ii:
for any term x. Note that although ((S One thousand K)
x) = (We x) for any ten, (S One thousand K)
itself is non capable I personally. You say a terms come extensionally equal. Extensional equality captures the
mathematical notion of the equality of functions: that ii functions
come 'match' whenever it universally make a equivalent final result for the same
arguments. Within direct contrast, a terms themselves capture a notion of
intensional equality of functions: that ii functions come 'peer'
single whenever it own monovular implementations. There are numerous ways to
implement an identity work; (S 1000 K) & I
come among these ways. (S Thousand S) is eventually a second. We
may utilize a word same to show extensional equality,
reserving peer for monovular combinatorial terms.
The supplementary interesting combinator is the fixed point combinator or Y combinator, which can be utilized to implement recursion.
Completeness of the S-K basis
These are the mayhap astonishing fact that S & K can be
composed to green goods combinators that come extensionally equal to
any lambda term, & so, by Church's thesis, to any
estimable work whatsoever. the proof is to present a transformation,
T[ ], which converts an arbitrary lambda term into an equivalent
combinator.
T[ ] can be defined when follows:
T[V] => V
T[(E1 E2)] => (T[E1] T[E2])
T[λx.E] => (M T[E]) (whenever x is non loose inside E)
T[λx.x] => I
T[λx.λy.E] => T[λx.T[λy.E]] (if x is free in E)
T[λx.(E1 E2)] => (S T[λx.E1] T[λx.E2])
Conversion of a lambda term to an equivalent combinatorial term
For example, we will convert the lambda term λx.λy.(y x) to a
combinator:
If we apply this combinator to any two terms x and y, it
reduces as follows:
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[ ] construction may expand a lambda
term of length n to a combinatorial term of length
Θ(3n).
Explanation of the T[ ] transformation
The T[ ] 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 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.
It's 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.(E1 E2) is a function which takes an argument, say a, and
substitutes it into the lambda term (E1 E2) in place of x,
yielding (E1 E2)[x : = a]. But substituting a into (E1 E2) in place
of x is just the same as substituting it into both E1 and E2, so
(E1 E2)[x := a] = (E1[x := a] E2[x := a])
(λx.(E1 E2) a) = ((λx.E1 a) (λx.E2 a))
= (S λx.E1 λx.E2 a)
= ((S λx.E1 λx.E2) a)
By extensional equality,
λx.(E1 E2) = (S λx.E1 λx.E2)
Therefore, to find a combinator equivalent to λx.(E1 E2), it is
sufficient to find a combinator equivalent to (S λx.E1 λx.E2), and
(S T[λx.E1] T[λx.E2])
evidently fits the bill. E1 and E2 each contain strictly fewer
applications than (E1 E2), 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.
Simplifications of the transformation
η-reduction
The combinators generated by the T[ ] transformation can be made
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.
Taking this simplification into account, the example above becomes:
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:
(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[] 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 into I.
Combinators B, C of Curry
The combinators S and K already figure in the work of Schönfinkel (although symbol C was used instead of present K), Curry introduced the use of B, C, W (and K), already in his doctoral thesis of 1930 (see B,C,K,W System). In Combinatory Logic V. I, we return to S, K but, (via Markov's algorithms) he uses B and C to simplify many reductions. This seems to have been used, much later, by David Turner, whose name has been bound to its computational use. Two new combinators are introduced:
(C a b c) = (a c b)
(B a b c) = (a (b c))
Using these combinators, we can extend the rules for the
transformation as follows:
T[V] => V
T[(E1 E2)] => (T[E1] T[E2])
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.(E1 E2)] => (S T[λx.E1] T[λx.E2]) (if x is free in both E1 and E2)
T[λx.(E1 E2)] => (C T[λx.E1] E2) (if x is free in E1 but not E2)
T[λx.(E1 E2)] => (B E1 T[λx.E2]) (if x is free in E2 but not E1)
Using B and C combinators, the transformation of
λx.λy.(y x) looks like this:
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)
= C*(traditional canonical notation : X* = X I)
= I'(traditional canonical notation: X' = C X)
And indeed, (C I x y) does reduce to (y x):
(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
substitution only in the applicand, and B only in the argument.
Reverse conversion
The conversion L[ ] from combinatorial terms to lambda terms is
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[(E1 E2)] = (L[E1] L[E2])
Note, however, that this transformation is not the inverse
transformation of any of the versions of T[ ] that we have seen.
Undecidability of combinatorial calculus
It is undecidable whether a general combinatory term has a normal
form; whether two combinatory terms are equivalent, etc. This is
equivalent to the undecidability of the corresponding problems for
lambda terms. However, a direct proof is as follows:
First, observe that the term
Ω = (S I I (S I I))
has no normal form, because it reduces to itself after three steps, as
follows:
(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
(N x) => T, if x has a normal form
F, otherwise.
(Where T and F the transformations of the conventional
lambda-calculus definitions of true and false, λx.λy.x and λx.λy.y.
The combinatory versions have T = K and F = (K I).)
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:
(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:
(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:
(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.
Combinatory terms as graphs
(TO DO: Add details with illustrations; don't forget to discuss the effect of
fixed-point combinators.)
Applications
Compilation of functional languages
Functional programming languages are often based on the simple but
universal semantics of the lambda calculus. (Add details.)
David Turner used his combinators to implement the SASL language.
(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.)
Logic
The Curry-Howard isomorphism implies a relationship between logic
and programming: Every valid proof of a theorem of logic corresponds
directly to a reduction of a lambda term, and vice versa. Theorems
themselves are identified with function type signatures. Specifically, typed combinatory logics
correspond to Hilbert systems in proof theory.
(Add: Demonstration that the axioms
(a -> a)
(a -> b -> a)
(a -> b -> c) -> (a -> b) -> (a -> c)
are complete for the intuitionistic fragment of propositional logic.)
See also:
graph reduction machine
supercombinators
|