|
|
Line 105: |
Line 105: |
|
|
|
|
|
</source> |
|
</source> |
|
|
|
|
|
== Conversion without lifting == |
|
|
|
|
|
The ''let'' expression, is useful in describing lifting and dropping, and in describing the relationship between recursive equations and lambda expressions. The "let" expression is present in many functional languages to allow the local definition of expression, for use in defining another expression. The "let" expression may be generalized slightly to allow equations to be used in defining the local expression. A let expression then looks like, |
|
|
|
|
|
: <math>\operatorname{let} f : E \operatorname{in} L </math> |
|
|
where, |
|
|
: ''f'' is a variable name, where f has a local scope. |
|
|
: E is a Boolean expression. |
|
|
: L is a Lambda expression. |
|
|
|
|
|
The following rules describe the equivalence of lambda and let expressions, |
|
|
|
|
|
{| class="wikitable" |
|
|
|- |
|
|
! Name !! Law |
|
|
|- |
|
|
| lambda-param || <math>f\ x = y \equiv f = \lambda x.y </math> |
|
|
|- |
|
|
| lambda-let || <math>\operatorname{let} f : f = E \operatorname{in} L \equiv \lambda f.L\ E) </math> (where f is a variable name). |
|
|
|- |
|
|
| let-let || <math>f \not \in FV(F) \to (\operatorname{let} f : f = e \and F \operatorname{in} L \equiv \operatorname{let} F \operatorname{in} \operatorname{let} f : f = e \operatorname{in} L) </math> (where f is a variable name). |
|
|
|} |
|
|
|
|
|
Meta-functions will be given that describe the conversion between ''lambda'' and ''let'' expressions. A meta-function is a function that takes a program as a parameter. The program is data for the meta-program. The program and the meta program are at different meta-levels. |
|
|
|
|
|
The following conventions will be used to distinguish program from the meta program, |
|
|
* Square brackets [] will be used to represent function application in the meta program. |
|
|
* Capital letters will be used for variables in the meta program. Lower case letters represent variables in the program. |
|
|
* <math> \equiv </math> will be used for equals in the meta program. |
|
|
|
|
|
For simplicity the first rule given that matches will be applied. |
|
|
|
|
|
=== Conversion from Lambda to Let expressions === |
|
|
|
|
|
The following rules describe how to convert from a Lambda expression to a ''let'' expresion, without altering the structure. |
|
|
# <math> \operatorname{de-lambda}[(\lambda F.E) L] \equiv \operatorname{let-combine}[\operatorname{let} F : \operatorname{de-lambda}[F = L] \operatorname{in} E] </math> |
|
|
# <math> V \not \in \operatorname{FV}[\lambda F.E] \to \operatorname{de-lambda}[\lambda F.E] \equiv \operatorname{let-combine}[\operatorname{let} V : \operatorname{de-lambda}[V\ F = E] \operatorname{in} V] </math> |
|
|
# <math> \operatorname{de-lambda}[M\ N] \equiv \operatorname{de-lambda}[M]\ \operatorname{de-lambda}[N] </math> |
|
|
# <math> \operatorname{de-lambda}[V] \equiv V </math> |
|
|
# <math> \operatorname{de-lambda}[F = \lambda P.E] \equiv \operatorname{de-lambda}[F\ P = E] </math> |
|
|
# <math> \operatorname{de-lambda}[E = F] \equiv \operatorname{de-lambda}[E] = \operatorname{de-lambda}[F] </math> |
|
|
# <math> V \ne W \to \operatorname{let-combine}[\operatorname{let} V : E \operatorname{in} \operatorname{let} W : F \operatorname{in} G] \equiv \operatorname{let} V, W : E \and F \operatorname{in} G </math> |
|
|
# <math> \operatorname{let-combine}[\operatorname{let} V : E \operatorname{in} F] \equiv \operatorname{let} V : E \operatorname{in} F </math> |
|
|
|
|
|
For example the [[Fixed-point combinator|Y combinator]], |
|
|
: <math>\lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x)) </math> |
|
|
{| class="wikitable mw-collapsible mw-collapsed" |
|
|
|- |
|
|
! Rule !! Lambda Expression |
|
|
|- |
|
|
| 2 || <math>\operatorname{de-lambda}[\lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x))] </math> |
|
|
|- |
|
|
| 6, 3 || <math>\operatorname{let} p : \operatorname{de-lambda}[p\ f = (\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x))] \operatorname{in} p </math> |
|
|
|- |
|
|
| 2 || <math>\operatorname{let} p : p\ f = \operatorname{de-lambda}[(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x))] \operatorname{in} p </math> |
|
|
|- |
|
|
| 1 || <math>\operatorname{let} p : p\ f = \operatorname{let} x : \operatorname{de-lambda}[x = \lambda q.f\ (q\ q)] \operatorname{in} f\ (x\ x) \operatorname{in} p </math> |
|
|
|- |
|
|
| 5 || <math>\operatorname{let} p : p\ f = \operatorname{let} x : \operatorname{de-lambda}[x\ q = f\ (q\ q)] \operatorname{in} f\ (x\ x) \operatorname{in} p </math> |
|
|
|- |
|
|
| 6, 3 || <math>\operatorname{let} p : p\ f = \operatorname{let} x : x\ q = f\ (q\ q) \operatorname{in} f\ (x\ x) \operatorname{in} p </math> |
|
|
|} |
|
|
|
|
|
=== Conversion from Let to Lambda expressions === |
|
|
|
|
|
These rule reverse the conversion described above. They convert from a ''let'' expression to a Lambda expresion, without altering the structure. Not all let expressions may be converted using these rules. |
|
|
|
|
|
# <math> \operatorname{de-let}[\operatorname{let} F : G \operatorname{in} F] \equiv \operatorname{get-lambda}[F, G] = </math> |
|
|
# <math> \operatorname{de-let}[\operatorname{let} F : G \operatorname{in} E] \equiv (\lambda F.\operatorname{de-let}[E])\ \operatorname{get-lambda}[F, G] = </math> |
|
|
# <math> \operatorname{de-let}[\lambda V.E] \equiv \lambda V.\operatorname{de-let}[E] </math> |
|
|
# <math> \operatorname{de-let}[M\ N] \equiv \operatorname{de-let}[M]\ \operatorname{de-let}[N] </math> |
|
|
# <math> \operatorname{de-let}[V] \equiv V </math> |
|
|
# <math> \operatorname{get-lambda}[F, G\ V = E] = \operatorname{get-lambda}[F, G = \lambda V.E] </math> |
|
|
# <math> \operatorname{get-lambda}[F, F = E] = \operatorname{de-let}[E] </math> |
|
|
# <math> W \not \in \operatorname{FV}[E] \to \operatorname{de-let}[\operatorname{let} V, W : E \and F \operatorname{in} G] \equiv \operatorname{de-let}[\operatorname{let} V : E \operatorname{in} \operatorname{let} W : F \operatorname{in} G] </math> |
|
|
|
|
|
For example the ''let'' expression obtained from the [[Fixed-point combinator|Y combinator]], |
|
|
: <math>\operatorname{let} p : p\ f = \operatorname{let} x : x\ q = f\ (q\ q) \operatorname{in} f\ (x\ x) \operatorname{in} p </math> |
|
|
|
|
|
{| class="wikitable mw-collapsible mw-collapsed" |
|
|
|- |
|
|
! Rule !! Lambda Expression |
|
|
|- |
|
|
| 1 || <math>\operatorname{de-let}[\operatorname{let} p : p\ f = \operatorname{let} x : x\ q = f\ (q\ q) \operatorname{in} f\ (x\ x) \operatorname{in} p] </math> |
|
|
|- |
|
|
| 6 || <math>\operatorname{get-lambda}[p, p\ f = \operatorname{let} x : x\ q = f\ (q\ q) \operatorname{in} f\ (x\ x)] </math> |
|
|
|- |
|
|
| 7 || <math>\operatorname{get-lambda}[p, p = \lambda f.\operatorname{let} x : x\ q = f\ (q\ q) \operatorname{in} f\ (x\ x)] </math> |
|
|
|- |
|
|
| 3 || <math>\operatorname{de-let}[\lambda f.\operatorname{let} x : x\ q = f\ (q\ q) \operatorname{in} f\ (x\ x)] </math> |
|
|
|- |
|
|
| 2, 4, 5 || <math>\lambda f.\operatorname{de-let}[\operatorname{let} x : x\ q = f\ (q\ q) \operatorname{in} f\ (x\ x)] </math> |
|
|
|- |
|
|
| 6 || <math>\lambda f.(\lambda x.f\ (x\ x))\ \operatorname{get-lambda}[x, x\ q = f\ (q\ q)] </math> |
|
|
|- |
|
|
| 7 || <math>\lambda f.(\lambda x.f\ (x\ x))\ \operatorname{get-lambda}[x, x = \lambda q.f\ (q\ q)] </math> |
|
|
|- |
|
|
| 3, 4, 5 || <math>\lambda f.(\lambda x.f\ (x\ x))\ \operatorname{de-let}[\lambda q.f\ (q\ q)] </math> |
|
|
|- |
|
|
| || <math>\lambda f.(\lambda x.f\ (x\ x))\ (\lambda q.f\ (q\ q)) </math> |
|
|
|} |
|
|
|
|
|
For a second example take the lifted version of the [[Fixed-point combinator|Y combinator]], derived in [[#Lambda Lifting|Lambda Lifting]] |
|
|
:<math>\operatorname{let}p, q : p\ f\ x = f\ (x\ x) \and q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p </math> |
|
|
|
|
|
{| class="wikitable mw-collapsible mw-collapsed" |
|
|
|- |
|
|
! Rule !! Lambda Expression |
|
|
|- |
|
|
| 8 || <math>\operatorname{de-let}[\operatorname{let}p, q : p\ f\ x = f\ (x\ x) \and q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p] </math> |
|
|
|- |
|
|
| 2 || <math>\operatorname{de-let}[\operatorname{let} p : p\ f\ x = f\ (x\ x) \operatorname{in} \operatorname{let} q : q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p] </math> |
|
|
|- |
|
|
| 6, 7 || <math> (\lambda p.\operatorname{de-let}[\operatorname{let} q : q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p])\ \operatorname{get-lambda}[p, p\ f\ x = f\ (x\ x)] </math> |
|
|
|- |
|
|
| 2, 4, 5 || <math> (\lambda p.\operatorname{de-let}[\operatorname{let} q : q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p])\ \lambda f.\lambda x.f\ (x\ x) </math> |
|
|
|- |
|
|
| 6, 7 || <math> (\lambda p.(\lambda q.q\ p)\ \operatorname{get-lambda}[q, q\ p\ f = (p\ f)\ (p\ f)])\ \lambda f.\lambda x.f\ (x\ x) </math> |
|
|
|- |
|
|
| || <math> (\lambda p.(\lambda q.q\ p)\ \lambda p.\lambda f.(p\ f)\ (p\ f))\ \lambda f.\lambda x.f\ (x\ x) </math> |
|
|
|} |
|
|
|
|
|
== Lambda Lifting in Lambda calculus == |
|
== Lambda Lifting in Lambda calculus == |
Lambda lifting is the process of eliminating free variables from local function definitions from a computer program. The elimination of free variables allows the compiler to hoist local definitions out of their surrounding contexts into a fixed set of top-level functions with an extra parameter replacing each local variable. By eliminating the need for run-time access-links, this may reduce the run-time cost of handling implicit scope. Many functional programming language implementations use lambda lifting during compilation.[citation needed]
The term "lambda lifting" was first introduced by Thomas Johnsson around 1982.
Lambda lifting is not the same as closure conversion. Lambda lifting requires all call sites to be adjusted (adding extra arguments to calls) and does not introduce a closure for the lifted lambda expression. In contrast, closure conversion does not require call sites to be adjusted but does introduce a closure for the lambda expression mapping free variables to values.
The reverse operation is called lambda dropping.[1]
Algorithm
The following algorithm is one way to lambda-lift an arbitrary program in a language which doesn't support closures as first-class objects:
- Rename the functions so that each function has a unique name.
- Replace each free variable with an additional argument to the enclosing function, and pass that argument to every use of the function.
- Replace every local function definition that has no free variables with an identical global function.
- Repeat steps 2 and 3 until all free variables and local functions are eliminated.
If the language has closures as first-class objects that can be passed as arguments or returned from other functions, the closure will need to be represented by a data structure that captures the bindings of the free variables.
Example
The following OCaml program computes the sum of the integers from 1 to 100:
let rec sum n =
if n = 1 then
1
else
let f x =
n + x in
f (sum (n - 1)) in
sum 100
(The let rec
declares sum
as a function that may call itself.) The function f, which adds sum's argument to the sum of the numbers less than the argument, is a local function. Within the definition of f, n is a free variable. Start by converting the free variable to an argument:
let rec sum n =
if n = 1 then
1
else
let f w x =
w + x in
f n (sum (n - 1)) in
sum 100
Next, lift f into a global function:
let rec f w x =
w + x
and sum n =
if n = 1 then
1
else
f n (sum (n - 1)) in
sum 100
The following is the same example, this time written in JavaScript:
// Initial version
function sum (n) {
function f (x) {
return n + x;
}
if (n == 1) {
return 1;
}
else {
return f( sum(n - 1) );
}
}
// After converting the free variable n to a formal parameter w
function sum (n) {
function f (w, x) {
return w + x;
}
if (n == 1) {
return 1;
}
else {
return f( n, sum(n - 1) );
}
}
// After lifting function f into the global scope
function f (w, x) {
return w + x;
}
function sum (n) {
if (n == 1) {
return 1;
}
else {
return f( n, sum(n - 1) );
}
}
Conversion without lifting
The let expression, is useful in describing lifting and dropping, and in describing the relationship between recursive equations and lambda expressions. The "let" expression is present in many functional languages to allow the local definition of expression, for use in defining another expression. The "let" expression may be generalized slightly to allow equations to be used in defining the local expression. A let expression then looks like,
where,
- f is a variable name, where f has a local scope.
- E is a Boolean expression.
- L is a Lambda expression.
The following rules describe the equivalence of lambda and let expressions,
Name |
Law
|
lambda-param |
|
lambda-let |
(where f is a variable name).
|
let-let |
(where f is a variable name).
|
Meta-functions will be given that describe the conversion between lambda and let expressions. A meta-function is a function that takes a program as a parameter. The program is data for the meta-program. The program and the meta program are at different meta-levels.
The following conventions will be used to distinguish program from the meta program,
- Square brackets [] will be used to represent function application in the meta program.
- Capital letters will be used for variables in the meta program. Lower case letters represent variables in the program.
- will be used for equals in the meta program.
For simplicity the first rule given that matches will be applied.
Conversion from Lambda to Let expressions
The following rules describe how to convert from a Lambda expression to a let expresion, without altering the structure.
For example the Y combinator,
Rule |
Lambda Expression
|
2 |
|
6, 3 |
|
2 |
|
1 |
|
5 |
|
6, 3 |
|
Conversion from Let to Lambda expressions
These rule reverse the conversion described above. They convert from a let expression to a Lambda expresion, without altering the structure. Not all let expressions may be converted using these rules.
For example the let expression obtained from the Y combinator,
Rule |
Lambda Expression
|
1 |
|
6 |
|
7 |
|
3 |
|
2, 4, 5 |
|
6 |
|
7 |
|
3, 4, 5 |
|
|
|
For a second example take the lifted version of the Y combinator, derived in Lambda Lifting
Rule |
Lambda Expression
|
8 |
|
2 |
|
6, 7 |
|
2, 4, 5 |
|
6, 7 |
|
|
|
Lambda Lifting in Lambda calculus
This section describes lambda lifting in more detail, and describes the process when used in Lambda Calculus. Lambda lifting may be used to convert a program written in Lambda Calculus into a functional program, without lambdas. This demonstrates the equivalence of programs written in Lambda Calculus and programs written as functions.[2]
Each Lambda Lift takes a lambda abstraction which is a sub expression of a lambda expression and replaces it by a function call (application) to a function that it creates. The free variables in the sub expression are the parameters to the function call. The process is similar to refactoring out code and putting it in a function. Lambda Lifts may be repeated until the expression has no lambda abstractions.
The purpose of lambda lifting
Lambda lifting converts a program with lambda expressions into a program with function calls only. Function calls may be implemented using a stack based implementation, which is simple and efficient.
However a stack based implementation must be strict. A functional language is normally implemented using a lazy strategy, which delays calculation until the value is needed. The lazy implementation strategy gives flexibility to the programmer.
Also an efficient implementation of Lamba lifting is O(n 2) on processing time for the compiler. [3]
Lambda lifting gives a direct translation of a Lambda calculus program into a functional program. At first site this would indicate the soundness of Lambda calculus as a deductive system. However this is not the case as the eta reduction used in Lambda lifting is the step that introduces cardinality problems into the Lambda calculus, because it removes the value from the variable, without first checking that there is only one value that satisfies the conditions on the variable.
Lambda lifting is useful in understanding the relationship between function definitions and lambda expressions.
This meta-function lambda-lift-tran transforms any lambda expression into a set of functions defined without lambda abstractions. For example,
The algorithm described here regards every abstraction as an anonymous function. This transformation names the anonymous function and lifts. Alternative approaches are possible. A lambda abstraction applied to an expression may be regarded as a local function definition.
A meta-function is a function that takes a program as a parameter. The program is data for the meta-program. The program and the meta program are at different meta-levels.
The following conventions will be used to distinguish program from the meta program,
- Square brackets [] will be used to represent function application in the meta program.
- Capital letters will be used for variables in the meta program. Lower case letters represent variables in the program.
- will be used for equals in the meta program.
Calling lambda-lift-tran on a lambda expression gives you a functional program in the form,
where M is a series of function definitions, and N is the expression representing the value returned.
The processing of transforming the lambda expression is a series of lifts. Each lift has,
- A sub expression chosen for it by the function candidate-prefix-lambda. The sub expression should be chosen so that it may be converted into an equation with no lambdas.
- The lift is performed by a call to the lambda-lift meta function, described in the next section,
-
Rules for Lambda lifting
The lambda-lift meta function performs a single lambda lift, which takes an expression and replaces it with a function call.
The lift is given a sub-expression (called S) to be lifted. For S;
- Create a name for the function that will replace S (called H). Make sure that the name identified by H has not been used.
- Add parameters to H, for all the free variables in S, to create an expression G (see make-call).
The lambda lift is the substitution of an expression for function application, along with the addition of a definition for the function.
The new lambda expression has S substituted for G. Note that L[S:=G] means substitution of S for G in L. The function definitions has the function definition G = S added.
In the above rule G is the function application that is substituted for the expression S. It is defined by,
where H is the function name, and FV returns a set of variables that are free in the expression. H must be a new variable, i.e. a name not already used in the lambda expression,
where is a meta function that returns the set of variables used in E.
For example,
gives,
Constructing the call
The function call G is constructed by adding parameters for each variable in the free variable set (represented by V), to the function H,
For example,
Eta reductions to remove lambda abstractions in lifted expressions
An eta reduction is ,
If you assume that the eta-redex of an expression equals the expression, this can be rearranged as,
The de-lambda meta function applies eta-reductions to remove lambda abstractions. It is defined by,
- if E is not a lamba abstraction
For example,
Candidate prefix lambda for lifting
The candidate-prefix-lambda is a meta function that returns a lambda abstraction within an expression whose body does not contain any lambda abstractions. The lambda abstraction may have a number of parameters, as they can be removed by the de-lambda meta function defined previously.
The rules are described below,
-
-
- where x is a variable.
Example
For example the Y combinator,
|
Lambda Expression |
Function |
From |
To |
Variables
|
1 |
|
true |
|
|
|
2 |
|
|
|
|
|
3 |
|
|
|
|
|
4 |
|
|
|
|
|
5 |
|
|
|
|
|
The first sub expression to be chosen for lifting is . This transforms the lambda expression into and creates the equation .
The second sub expression to be chosen for lifting is . This transforms the lambda expression into and creates the equation .
And the result is,
Because is a global function, the result could also have been written,
This would be generated if there was a change to make-call so that only free variables that are not global are added as parameters. More sophisticated versions of the lambda lifting algorithm exist that have processing time O(n 2), and derive the minimum set of parameters required. [3]
Execution
Apply function to,
|
|
|
|
|
|
So,
or
The Y-Combinator calls its parameter (function) repeatedly on itself. The value is defined if the function has a fixed point. But the function will never terminate.
Lambda dropping in Lambda Calculus
Lambda dropping [4] is making the scope of functions smaller and using the context from the reduced scope to reduce the number of variables. Reducing the number of variables makes functions easier to comprehend.
Lambda dropping also may make the compilation of programs quicker for the compiler, and may also increase the efficiency of the resulting program, by reducing the number of parameters, and reducing the size of stack frames.
However Lambda dropping also makes a function harder to re-use. A dropped function is tied to its context, and can only be used in a different context if it is first lifted.
In the Lambda Lifting section, a meta function for first lifting and then converting the resulting lambda expression into recursive equation was described. The Lamda Drop meta function performs the reverse by first converting recursive equations to lambda abstractions, and then dropping the resulting lambda expression, into the smallest scope which covers all references to the lambda abstraction.
Rules used in Lambda dropping
A let expression may be converted back into a lambda expression by repeated application of the lambda-param and the lambda-equiv law,
Name |
Law
|
lambda-param |
|
lambda-equiv |
(where f is a variable name).
|
Converting equations to lambda expressions
This meta-function lambda-abstract-tran transforms an expression defined using functions with a let expression to a lambda expression. The transformation works when the let condition is structured like a series of functions, but does not work for arbitrary expressions.
The lambda-lift-tran meta function described earlier creates "let" expressions where each function definition has no free variables. lambda-abstract-tran needs functions with no free variables to work correctly.
For example,
lambda-abstract-tran is defined as,
Lambda abstract performs three separate processing steps; pre-process, process, and convert. These steps are described below,
Pre-process - Split into separate lets,
After lambda-preprocess the result for the example is,,
Process - Turn functions into lambdas,
- ..... Use this case when E is not a let expression.
After lambda-process,
Convert - Turn lets into lambdas,
- ..... Use this case when E is not a let expression.
Then after lambda-abstract-tran,
The abstract meta function removes parameters from functions using lambda abstractions. It is defined by,
- if K is a variable.
For example,
Abstraction Sinking
Abstraction sinking is moving abstractions so that they have the smallest scope that covers the references to the abstraction variable. Lambda-drop-tran converts recursive equations to lambda expression, and then sinks the resulting abstractions.
rename is a meta function to give all the abstractions distinct names. This step is important because in the renaming steps, the name will be used to identify an abstraction.
sink-tran sinks each abstraction, starting from the innermost,
Sinking is moving a lambda abstraction inwards as far as possible such that it is still outside all references to the variable.
Application - 4 cases.
Abstraction - Only 1 case as the names of the lambda abstractions have been made distinct by rename.
Variable - 2 cases.
For the example above, sinking,
Sinking a second time,
Parameter Dropping
Parameter dropping is optimizing a function for its position in the function. Lambda lifting added parameters that were necessary so that a function can be moved out of its context. In dropping, this process is reversed, and extra parameters that contain variables that were free may be removed.
Dropping a parameter is removing an unnecessary parameter from a function, where the actual parameter being passed in is always the same expression. The free variables of the expression must also be free where the function is defined. In this case the parameter that is dropped is replaced by the expression in the body of the function definition. This makes the parameter unnecessary.
For example, consider,
In this example the actual parameter for the formal parameter o is always p. As p is a free variable in the whole expression, the parameter may be dropped. The actual parameter for the formal parameter y is always n. However n is bound in a lambda abstraction. So this parameter may not be dropped.
The result of dropping the parameter is,
-
For the main example,
-
The definition of drop-params-tran is,
where,
Build parameter lists
For each abstraction that defines a function, build the information required to make decisions on dropping names. This information consists of information about each parameter; the parameter name, the expression for the actual value, and an indication that all the expressions have the same value.
For example in,
the parameters to the function g are,
Formal Parameter |
All Same Value |
Actual parameter expression
|
x |
false |
_
|
o |
true |
p
|
y |
true |
n
|
Each abstraction is renamed with a unique name, and the parameter list is associated with the name of the abstraction. For example, for g there is the parameter list;
build-param-lists builds all the lists for an expression, by traversing the expression.
Abstraction - A lambda expression of the form is analyzed to extract the names of parameters for the function.
Locate the name and start building the parameter list for the name, filling in the formal parameter names. Also receive any actual parameter list from the body of the expression, and return it as the actual parameter list from this expression
Variable - A call to a function.
For a function name or parameter start populating actual parameter list by outputting the parameter list for this name.
Application - An application (function call) is processed to extract parameter information.
-
Retrieve the parameter lists for the expression, and the parameter. Retrieve a parameter record from the parameter list from the expression, and check that the current parameter value matches this parameter. Record the value for the parameter name for use later in checking.
- ... if N is a variable.
- ... otherwise.
The logic for equate is used in this more difficult example,
has the parameter x dropped to become,
|
function |
param 1 |
param 2
|
Abstract |
p |
p |
x
|
Application 1 |
p |
p |
f
|
Application 2 |
q |
q |
x
|
q in the second call has the value of p. For the second parameter, f and x are the same value. This is picked up by using the condition, . The condition supports the functions q and p sharing the same parameter list, which is also needed in this example.
Retrieving the "same value" indicator from the parameter lists is a little unusual. The same value indicator is never set to true. It is only set to false if all the values cannot be matched. The value is retrieved by using S to build a set of the Boolean values allowed for S. If true is a member then all the values for this parameter are equal, and the parameter may be dropped.
Drop parameters
Abstraction - Two cases; abstraction with application, abstraction aloe
Abstraction with application. Drop the actual parameters in the body of the abstraction, based on the parameter lists. Also drop lambda abstractions for the parameters in the application of the abstraction.
where,
Abstraction alone. Use this case only if there is no application. Drop parameters in the body of the abstraction based on the parameter lists.
Variable.
Application - Two cases; parameter dropped or not dropped. Use this case only when the function expression E is not an abstraction.
drop-formal removes formal parameters, based on the contents of the parameter lists. Its parameters are,
- The parameter list,
- The function definition (lambda abstraction).
- The free variables from the function definition.
drop-formal has 2 cases; parameter dropped, parameter not dropped.
Which can be explained as,
- If all the actual parameters have the same value, and all the free variables of that value are available for definition of the function then drop the parameter, and replace the old parameter with it's value.
- else do not drop the parameter.
- else return the body of the function.
For example,
Rule |
Condition |
Expression
|
2
|
|
|
1
|
|
|
2
|
)
|
|
3
|
|
|
|
|
|
Example
Starting with the function definition of the Y-combinator,
Transformation |
Expression
|
|
|
lambda-preprocess
|
|
lambda-process
|
|
lambda-convert
|
|
sink-tran
|
|
sink-tran
|
|
drop-param
|
|
beta-redex
|
|
Which gives back the Y combinator,
See also
References
External links