the concept of λ-definissability was the first of what is accepted now like the exact equivalent of mathematical descriptions for which algorithms exist. Stephen Kleene in Origins off Recursive Function Theory , Year off the history off Computing, 1081, flight; 3, n°1, page 52
The lambda-calculation (or λ-calculation ) is a theoretical Computer programming language invented by Alonzo Church in the Années 1930. It makes it possible to the mathematicians to work in particular on the concepts of function and application. It also finds many applications in the field of the proof.
This language was the first used to define and to characterize the functions recursive S. It has a great importance in the theory of the Calculabilité, with equal of the machines of Turing and the Modèle of Herbrand-Gödel.
It is about a model of calculation, i.e. a formalization of the concept of calculation. One can simulate the standardization λ-terms using a machine of Turing, and simulate a machine of Turing by λ-terms. These two models are thus equivalent (or Turing-equivalents). The Thèse of Church-Turing affirms that any algorithm can be calculated by lambda-calculation, therefore by the equivalence which any algorithm can be calculated by a machine of Turing. A program being an algorithm allowing to solve a given problem, we have the first computer programming language there.
The lambda typified calculations are at the origin of the functional computer programming languages like Lisp, Caml or Haskell: the theory of the standard brings a strong and sure semantics to them.
Lambda-calculation is related with the Combinatory logic due to Haskell Curry.
Formally, the lambda calculation is defined by three kinds of lambda-terms:
The application can be seen with like function, and like argument. is then the image of by the function .
The abstraction can also be interpreted so that: is the function
For practical reasons, one sometimes also introduces primitive constants and operations (for example natural entireties and operations + and * usual). All these primitives will hide lambda terms (cf below). Thus, the function which takes a parameter and adds 2 to him will be defined like . The " reduction finale" (standardization) of will be thus .
For parenthesizing, there are several formalisms:
is equivalent to:
For example in , X is free, but is dependant there (by Dy). This is the same expression as because was a local name there, just like is Z. On the other hand does not correspond to the same expression because X is free. Moreover the notation F (X) specifies that the whole of its variables (free) is {X}.
Just like the integral binds the variable of integration, the λ binds the variable which follows it.
Examples: in X is dependant, and there free. One can rewrite this term as follows: .
More complicated is also equivalent to
One defines the unit VL ( T ) of the free variable of a term T by recurrence:
If a lambda-term then does not have free variables one says that it is closed .
The most important tool for calculation is the substitution . This operation makes it possible to replace a variable by a term. Thanks to this mechanism, the reductions will be able “to calculate” the term (NB: it is what one does in manner machinale in traditional algebraic handling, whose lambda calculation is, precisely, a generalization and an abstraction).
The substitution in a lambda term T of a variable X by a term U is noted T: = U. It is said that one substitutes U for X in T, and one defines it by recurrence on T:
Examples:
Note:: the alpha-conversion, which makes it possible to identify y.v and z.v: = Z must be defined with precaution and before substitution. Indeed the substitution of Z in v is not yet available and poses the same problems of capture. Thus in the term x.y.xyz.z, one will not be able to re-elect X in there (one would obtain y.y.yyz.z) on the other hand one can re-elect X in Z.
The formal and correct definitions of alpha-conversion and substitution are in the book of J. - L. Krivine for example, but a good comprehension of the concept of associated, usual variables in mathematics, is largely enough to include/understand lambda-calculation.
Defined thus substitution is an external mechanism with lambda-calculation, one also says that it belongs to the méta-theory. It should be noted that certain work aims at introducing substitution like an internal mechanism with lambda-calculation, leading to what is called calculations of explicit substitutions .
The terms are trees with binary nodes (applications), unary nodes (λ-abstractions) and sheets (variables). The reductions make it possible to modify the tree, however the tree is not inevitably “smaller” after the operation. Example: if you reduce (λx.xxx) (λx.xxx) you will obtain (λx.xxx) (λx.xxx) (λx.xxx). The reduction holds its name owing to the fact that one will reduce a piece of the term: the rédex .
One calls rédex a term of the form (x.u) v. One defines the beta-contraction then (or reduction ) of (x.u) v like U: = v; one notes → the relation of reduction: thus (x.u) v give U: = v. Intuitively, (x.u) v are the value of the function x.u applied to the variable v . U being the image of X by the function (x.u), the image of v is obtained in substituent in U , X by v . Conversely U: = v are called the contractum (x.u) v.
Example of reduction :
(x.xy) has gives xy: = = ay has
One notes →* the transitive reflexive closing of the relation → of contraction (→* is called the beta-reduction ) and =β his symmetrical and transitive reflexive closing (called beta-conversion or beta-equivalence ).
Β-conversion makes it possible to make a " step back " starting from a term. That allows, for example, to find the term before a β-reduction. To pass from to .
One can write
One thus will travel by reductions, and flashbacks of M with Me.
One also rather frequently uses another operation, called eta-reduction (or its reverse the eta-expansion ), defined as follows: x.ux →η U, when X does not appear free in U. Indeed, ux interprête like the image of X by the function U . x.ux interprête then like the function which, with X , associates the image of X by U , therefore like the function U itself.
Lastly, if primitives were given, one can fix their calculative behavior by means of the rules of delta-reduction . For example, if one gave oneself the entireties and + like additional terms, the tables of addition will be used as delta-rules. As the primitives are by definition completely foreign with lambda-calculation, their rules of calculation can adopt a priori any form. However, if one wants to extend the properties mentioned below to the case of a calculation with primitives, one is brought to make some assumptions on the added rules.
The calculation of a lambda-term can be defined by its reduction. Its original form is the statement and the normal form is the result.
A lambda-term T is known as in normal form if no beta-contraction can be to him applied, i.e. if T does not contain any rédex. Or, if there does not exist any lambda-term U such as T → U.
Example:
It is said that a lambda-term T is normalisable if there exists a normal form U and a succession of t1 lambda-terms, …, tn such as T = t1, U = tn and for any I (1 ≤ I < N) ti → ti+1 or ti+1 → ti. Such a U is called the normal form of T.
It is said that a lambda term T is strongly normalisable if all the reductions starting from T are finished .
Examples:
If a term is strongly normalisable, then it is normalisable.
Theorem of Church-Rosser: is T and U two terms such as T =β U. There exists a term v such as T →* v and U →* v.
Theorem of the rhombus (or of junction): is T, u1 and u2 lambda-terms such as T →* u1 and T →* u2. Then there exists a lambda-term v such as u1 →* v and u2 →* v.
Thanks to the Théorème of Church-Rosser one can easily show the unicity of the normal form as well as the coherence of the lambda-calculation (i.e. there exist at least two nonbeta-convertible distinct terms).
Even if by restricting the valid terms by the types one generally keeps most interesting. Moreover thanks to the Isomorphisme of Curry-Howard one can connect a lambda calculation to a logic and by there a term corresponds to a proof. Intuitively it is very strong because that makes it possible to associate with a mathematical proof a computer program. It is on that part of the automatic and semi-automatic prouveurs is based.
One will use codings to create the usual objects of data processing. Thanks to these objects one can all calculate because one can simulate a machine of Turing. And thanks to the theorems of the Theory of the calculability one from of deduced that lambda-calculation is a universal model of calculation.
In the Syntax part, we saw that it is practical to define primitives. It is what we will do here.
true will be
false will be
This is only the definition of a coding, and one could define others of them.
We notice that:
We can thus deduce a lambda-term representing from it the alternative: yew-then-else . It is a function with three argument, which takes Boolean and two lambda terms, which turns over the first if the Boolean one is true and the second if not.
Our function is well checked:
One will see same manner as
From there we have also a lambda-term for the traditional Boolean operations:
We will use the Entiers of Church . N = λfx.f (F (… (F X)…)) = λfx.fnx with N F. For example 0 = λfx.x, 3 = λfx.f (F (F X)).
There are two manners of coding the function successor. Either by adding a F at the head or in tail. At the beginning we have N = λfx.fn X and we want λfx.fn+1 X. It is necessary to be able to add a F either at the beginning of F “under” the lambdas or for the end.
If we choose to put it at the head, it is necessary to be able to enter “under” the lambdas. For that it is necessary to thus create redex if N is our entirety it is necessary to make N F X, which gives fn X. By putting a F at the head we almost finished: F (N F X) → F (fn X) = fn+1 X. We should now remake the lambdas to rebuild an entirety of Church: λfx.f (N F X) = λfx.fn+1 X (we could of course have taken other names of variables that F and X at the preceding stage and thus we would have kept these names here). Finally to have the “function” successor it is of course necessary to take an entirety in parameter, therefore to add a lambda. We obtain λnfx.f (N F X). The reader will be able to check that (λnfx.f (N F X)) 3 = 4, with 3 = λfx.f (F (F X))) and 4 = λfx.f (F (F (F X)))).
The other functions are built with the same principle, by applying what it is necessary in F and X. For example addition in “concaténant” the two lambda-terms: λnpfx.n F (p F X).
To code the multiplication it is a little smarter: one will use F “to propagate” a function on all the term: λnpfx. (N (p F) X)
The exponential one is not commonplace as opposed to what its writing lets think, and during the reduction one is obliged to re-elect the variables: λnp.p N
The predecessor and the subtraction are not simple either. One will speak again about it further.
One can as follows define the test in 0: if0thenelse = λnab.n (λx.b) has, or by using Boolean the λn.n (λx.faux) true.
All that is not very intuitive then to be able to code algorithms one defines the function of iteration on the entireties: iterate = λnuv.n U v
The trick it is that v are the basic case and U a function on the case of recurrence.
For example the addition which comes from these equations
One thus will program by iteration with the successor on the basic case p. the lambda-term is thus λnp.iterate N successor p. One will notice that add N p →* N successor p.
One can code couples by C = λz.z has B where has is the first element and B the second. One will note this couple (has, b). To reach the two parts one uses π1 = λc.c (λab.a) and π2 = λc.c (λab.b). One will recognize Boolean the true and false in these expressions and one will leave the care to the reader to reduce π1 (λz.z has b)
One can notice that an entirety is a list which does not contain a key . By adding information one can build the lists in a way similar to the entireties: ; …; an = λgy. G a1 (… (G an there)…)
Same manner that one introduced an iteration on the entireties one introduces an iteration on the lists. the function liste_it is defined by λlxm.l X m as for the entireties. The concept is about the same one but there are small nuances. We will see for an example.
example: The length of a list is defined by
The principle of construction of the entireties, the couples and the lists spreads with the binary trees:
To define the predecessor with the entireties of Church, one needs ruser and to use the couples. The idea is to rebuild the predecessor by iteration: pred = λn.π1 (iterate N (λc. (π2 C, successor (π2 c))) (0,0)). One notes while passing that the predecessor on the natural entireties is not especially defined into 0. One arbitrarily adopted here the convention which it would be worth 0.
It is checked for example that pred 3 →* π1 (iterate 3 (λc. (π2 C, successor (π2 c))) (0,0)) →* π1 (2,3) →* 2.
One from of deduced that the subtraction is definable by: sub = λnp.iterate p pred N with convention that if p is larger than N, then sub N p is worth 0.
By combining predecessor and iterator, one obtains a recursor . This one is distinguished from the iterator by the fact that the function which passed in argument has access to the predecessor.
rec = λnfx.π1 (N (λc. (F (π2 c) (π1 c), successor (π2 c))) (X, 0))
The fixed controller of point makes it possible to make infinite loops. This is practical to program functions which are not expressed simply by iteration, such as the pgcd, and it is especially necessary to program partial functions.
The controller of point of fixed simplest is: Y = λf. (λx.f (X X))(λx.f (X X))
It is checked that some is G. Thanks to the controller of point of fixed, one can for example define a function which takes in argument a function and tests if this function argument returns true for at least an entirety: teste_annulation = λg.Y (λfn.ou (G N) (F (successor N))) 0.
For example, if one defines the alternate continuation of Boolean the true and false : alternate = nonfalse λn.iterate N, then, it is checked that: teste_annulation alternate →* or (alternate 0) (Y (λfn.ou (alternate N) (F successor N)) (successor 0)) →* or (alternate 1) (Y (λfn.ou (alternate N) (F successor N)) (successor 1)) →* true.
One can also define the pgcd: pgcd = Y (λfnp.if0thenelse (sub p N) (if0thenelse (sub N p) p (F p (sub N p))) (F N (sub p N))).
The recursor and the point fix are key ingredients allowing to show that all recursive partial Fonction is definable in λ-calculation when the entireties are interpreted by the entireties of Church. Reciprocally, the λ-terms can be coded by entireties and the reduction of the λ-terms is definable like a function (partial) recursive. Λ-calculation is thus a model of the Calculabilité
One introduces simple types on the terms, and one accepts only the well typified terms . In addition to a preoccupation of clearness and a comprehension, that makes it possible to have the strong standardization , i.e. for all the terms, all the reductions lead to a normal form (which is single for each starting term). In other words, all the calculations carried out in this context finish. N the other hand, the expressive capacity of this calculation is very limited (thus, the exponential one cannot be defined there, nor even the function ).
More formally, the types are built in the following way:
Intuitively, the second case represents the type of the functions accepting an element of the type and returning an element of the type .
A context is a whole of pairs of the form where is a variable and a type. A judgment of typing is a triplet (it is said whereas is well typified in ), recursively defined by:
If primitives were given, a type should be given them (via ). In the case of the rule of the abstraction, the addition of mask a possible preceding occurrence of the variable in .
Although this model makes it possible to calculate all that one wants with correct algorithms, theoretically one can much better do. In particular by the introduction of the variables of the type. That increases the complexity (from the comprehension point of view and nondata-processing) of the system but increases the expressive capacity considerably. For the lambdas calculations typified of the second order one can make terms which depend on types, of the types which depend on terms and of the types which depend on types. By making the combination of each one one obtains eight lambda-calculations that Barendregt models in the form of cube. The end of the cube opposed to that of simply typified lambda-calculation is the Calcul of constructions due to Thierry Coquand, and gave rise to the system cock.
| Random links: | 2004 in architecture | Mónica Cruz | Barby (the Ardennes) | Diddl | Leigh Julius |