Misplaced Pages

Lambda lifting: Difference between revisions

Article snapshot taken from Wikipedia with creative commons attribution-sharealike license. Give it a read and then ask your questions in the chat. We can research this topic together.
Browse history interactively← Previous editContent deleted Content addedVisualWikitext
Revision as of 05:29, 10 November 2013 editThepigdog (talk | contribs)Extended confirmed users5,174 edits Drop formal parameters← Previous edit Latest revision as of 02:56, 2 October 2024 edit undoSoftlavender (talk | contribs)Autopatrolled, Extended confirmed users, Pending changes reviewers, Rollbackers92,256 editsm Reverted edit by Akaibu (talk) to last version by OAbotTag: Rollback 
(222 intermediate revisions by 47 users not shown)
Line 1: Line 1:
{{Short description|Globalization meta-process}}
'''Lambda lifting '''is the process of eliminating ]s from local ]s from a ]. 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 ]. Many ] language implementations use lambda lifting during compilation.{{Citation needed|Due to using the present tense, this implies that modern FP implementations use lambda lifting and so deserves at least such two examples.|date=July 2013}}
'''Lambda lifting '''is a ] that restructures a ] so that functions are defined independently of each other in a global ]. An individual "lift" transforms a local ] into a global function. It is a two step process, consisting of;
* Eliminating ] in the function by adding parameters.
* Moving functions from a restricted scope to broader or global scope.


The term "lambda lifting" was first introduced by ] around 1982. The term "lambda lifting" was first introduced by Thomas Johnsson around 1982 and was historically considered as a mechanism for implementing ]s. It is used in conjunction with other techniques in some modern ]s.


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 ] 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. Lambda lifting is not the same as closure conversion. It requires all ]s to be adjusted (adding extra arguments to calls) and does not introduce a ] 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 technique may be used on individual functions, in ], to make a function usable outside the scope in which it was written. Lambda lifts may also be repeated, in order to transform the program. Repeated lifts may be used to convert a program written in ] into a set of ], without lambdas. This demonstrates the equivalence of programs written in lambda calculus and programs written as functions.<ref>{{cite conference
The reverse operation is called ].<ref>{{cite doi|10.1145/258994.259007}}</ref>
| last = Johnsson
| first = Thomas
| title = Lambda Lifting: Transforming Programs to Recursive Equations
| citeseerx = 10.1.1.48.4346 |isbn=3-540-15975-4 |doi=10.1007/3-540-15975-4_37
| editor-last=Jouannaud |editor-first=J.P. |series=Lecture Notes in Computer Science |volume=201
| book-title=Functional Programming Languages and Computer Architecture. FPCA 1985 |publisher=Springer
| year = 1985}}</ref> However it does not demonstrate the soundness of lambda calculus for deduction, as the ] used in lambda lifting is the step that introduces ] 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 (see ]).

Lambda lifting is expensive on processing time for the compiler. An efficient implementation of lambda lifting is <math>O(n^2)</math> on processing time for the compiler.<ref name="Optimal Lambda Lifting in Quadratic Time">
{{citation |
contribution = Optimal Lambda Lifting in Quadratic Time |
title = Implementation and Application of Functional Languages — Revised Selected Papers |
pages = 37–56 |
first1 = Marco T. |
last1 = Morazán |
first2 = Ulrik P. |
last2 = Schultz |
year = 2008 |
doi = 10.1007/978-3-540-85373-2_3 |
isbn = 978-3-540-85372-5 }}
</ref>

In the ], where the basic types are functions, lifting may change the result of ] of a lambda expression. The resulting functions will have the same meaning, in a mathematical sense, but are not regarded as the same function in the untyped lambda calculus. See also ].

The reverse operation to lambda lifting is ].<ref>{{Cite journal | last1 = Danvy | first1 = O. | last2 = Schultz | first2 = U. P. | doi = 10.1145/258994.259007 | title = Lambda-dropping | journal = ACM SIGPLAN Notices | volume = 32 | issue = 12 | pages = 90 | year = 1997 | doi-access = free }}</ref>

Lambda dropping 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 it 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.


==Algorithm== ==Algorithm==
Line 19: Line 50:
The following ] program computes the sum of the integers from 1 to 100: The following ] program computes the sum of the integers from 1 to 100:


<source lang="ocaml"> <syntaxhighlight lang="ocaml">
let rec sum n = let rec sum n =
if n = 1 then if n = 1 then
Line 28: Line 59:
f (sum (n - 1)) in f (sum (n - 1)) in
sum 100 sum 100
</syntaxhighlight>
</source>


(The <code>let rec</code> declares <code>sum</code> 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: (The <code>let rec</code> declares <code>sum</code> 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 a parameter:


<source lang="ocaml"> <syntaxhighlight lang="ocaml">
let rec sum n = let rec sum n =
if n = 1 then if n = 1 then
Line 39: Line 70:
let f w x = let f w x =
w + x in w + x in
f n (sum (n - 1)) in f n (sum (n - 1)) in
sum 100 sum 100
</syntaxhighlight>
</source>


Next, lift f into a global function: Next, lift f into a global function:


<source lang="ocaml"> <syntaxhighlight lang="ocaml">
let rec f w x = let rec f w x =
w + x w + x
Line 54: Line 85:
f n (sum (n - 1)) in f n (sum (n - 1)) in
sum 100 sum 100
</syntaxhighlight>
</source>


The following is the same example, this time written in ]: The following is the same example, this time written in ]:


<source lang="javascript"> <syntaxhighlight lang="javascript">
// Initial version // Initial version


function sum (n) { function sum(n) {
function f (x) { function f(x) {
return n + x; return n + x;
} }


if (n == 1) { if (n == 1)
return 1; return 1;
} else
return f(sum(n - 1));
else {
return f( sum(n - 1) );
}
} }


// After converting the free variable n to a formal parameter w // After converting the free variable n to a formal parameter w


function sum (n) { function sum(n) {
function f (w, x) { function f(w, x) {
return w + x; return w + x;
} }


if (n == 1) { if (n == 1)
return 1; return 1;
} else
return f(n, sum(n - 1));
else {
return f( n, sum(n - 1) );
}
} }


// After lifting function f into the global scope // After lifting function f into the global scope


function f (w, x) { function f(w, x) {
return w + x; return w + x;
} }


function sum (n) { function sum(n) {
if (n == 1) { if (n == 1)
return 1; return 1;
} else
return f(n, sum(n - 1));
else {
return f( n, sum(n - 1) );
}
} }
</syntaxhighlight>


== Lambda lifting versus closures ==
</source>


Lambda lifting and ] are both methods for implementing ] programs. It implements block structure by eliminating it. All functions are lifted to the global level. Closure conversion provides a "closure" which links the current frame to other frames. Closure conversion takes less compile time.
== Lambda Lifting in Lambda calculus ==


Recursive functions, and block structured programs, with or without lifting, may be implemented using a ] based implementation, which is simple and efficient. However a stack frame based implementation must be ]. The stack frame based implementation requires that the life of functions be ] (LIFO). That is, the most recent function to start its calculation must be the first to end.
This section describes lambda lifting in more detail, and describes the process when used in ]. 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.<ref>{{citation | last = Johnsson | first = Thomas | title = Lambda Lifting: Transforming Programs to Recursive Equations | url=http://www.cse.iitb.ac.in/~as/fpcourse/lambda-lifting.ps.gz | work=Conf. on Func. Prog. Languages and Computer Architecture. | publisher=ACM Press | year = 1985}}</ref>


Some functional languages (such as ]) are implemented using ], which delays calculation until the value is needed. The lazy implementation strategy gives flexibility to the programmer. Lazy evaluation requires delaying the call to a function until a request is made to the value calculated by the function. One implementation is to record a reference to a "frame" of data describing the calculation, in place of the value. Later when the value is required, the frame is used to calculate the value, just in time for when it is needed. The calculated value then replaces the reference.
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 "frame" is similar to a ], the difference being that it is not stored on the stack. Lazy evaluation requires that all the data required for the calculation be saved in the frame. If the function is "lifted", then the frame needs only record the ], and the parameters to the function. Some modern languages use ] in place of stack based allocation to manage the life of variables. In a managed, garbage collected environment, a ] records references to the frames from which values may be obtained. In contrast a lifted function has parameters for each value needed in the calculation.
=== The purpose of lambda lifting ===


== Let expressions and lambda calculus ==
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.


The ] is useful in describing lifting and dropping, and in describing the relationship between recursive equations and lambda expressions. Most functional languages have let expressions. Also, block structured programming languages like ] and ] are similar in that they too allow the local definition of a function for use in a restricted ].
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.


The ''let'' expression used here is a fully mutually recursive version of ''let rec'', as implemented in many functional languages.
Also an efficient implementation of Lamba lifting is O(n 2) on processing time for the compiler. <ref name="Optimal Lambda Lifting in Quadratic Time" />


Let expressions are related to ]. Lambda calculus has a simple syntax and semantics, and is good for describing Lambda lifting. It is convenient to describe lambda lifting as a translations from ''lambda'' to a ''let'' expression, and lambda dropping as the reverse. This is because ''let'' expressions allow mutual recursion, which is, in a sense, more lifted than is supported in lambda calculus. Lambda calculus does not support mutual recursion and only one function may be defined at the outermost global scope.
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.


] which describe translation without lifting are given in the ] article.
Lambda lifting is useful in understanding the relationship between function definitions and lambda expressions.


The following rules describe the equivalence of lambda and let expressions,
=== Lamba-Lift transform of a lambda expression to functions ===
{| class="wikitable"

|-
This meta-function ''lambda-lift-tran'' transforms any lambda expression into a set of functions defined without lambda abstractions. For example,
! Name !! Law
: <math> \operatorname{lambda-lift-tran} \equiv \operatorname{let} p\ f\ x = f\ (x\ x) \and q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p </math>
|-

| Eta-reduction equivalence || <math>f\ x = y \equiv f = \lambda x.y</math>
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.
|-
| Let-Lambda equivalence || <math>f \notin FV(E) \to (\operatorname{let} f : f = E \operatorname{in} L \equiv (\lambda f.L)\ E) \ \text{(where }f\text{ is a variable name.)}</math>
|-
| Let combination || <math>x \notin FV(E) \to (\operatorname{let} v, \dots, w, x : E \land F \operatorname{in} L \equiv \operatorname{let} v, \dots, w: E \operatorname{in} \operatorname{let} x : F \operatorname{in} L)</math>
|}


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. Meta-functions will be given that describe lambda lifting and dropping. 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, The following conventions will be used to distinguish program from the meta program,
Line 137: Line 168:
* Capital letters will be used for variables in the meta program. Lower case letters represent variables in the 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. * <math> \equiv </math> will be used for equals in the meta program.
* <math> \_ </math> represents a dummy variable, or an unknown value.


For simplicity the first rule given that matches will be applied. The rules also assume that the lambda expressions have been pre-processed so that each lambda abstraction has a unique name.
Calling ''lambda-lift-tran'' on a lambda expression gives you a functional program in the form,
* let ''M'' in ''N''


The substitution operator is used extensively. The expression <math> L </math> means substitute every occurrence of ''G'' in ''L'' by ''S'' and return the expression. The definition used is extended to cover the substitution of expressions, from the definition given on the ] page. The matching of expressions should compare expressions for alpha equivalence (renaming of variables).
where ''M'' is a series of function definitions, and ''N'' is the expression representing the value returned.


== Lambda lifting in lambda calculus ==
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,


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.
* <math> \operatorname{lambda-lift-tran} = \operatorname{lambda-process}]</math>
* <math> \text{if } \operatorname{candidate-prefix-lambda} \text{ then } </math>
:: <math>\operatorname{lambda-process} = \operatorname{lambda-process}] </math>
: <math> \text{ else } </math>
:: <math> \operatorname{lambda-process} = L</math>


Lambda lifts may be used on individual functions, in ], to make a function usable outside the scope in which it was written. Such lifts may also be repeated, until the expression has no lambda abstractions, in order to transform the program.
=== Rules for Lambda lifting ===


=== Lambda lift ===
The ''lambda-lift'' meta function performs a single lambda lift, which takes an expression and replaces it with a function call.


A lift is given a sub-expression within an expression to lift to the top of that expression. The expression may be part of a larger program. This allows control of where the sub-expression is lifted to. The lambda lift operation used to perform a lift within a program is,
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'').


: <math> \operatorname{lambda-lift-op} =P] </math>
The lambda lift is the substitution of an expression for function application, along with the addition of a definition for the function.
: <math>\operatorname{lambda-lift} \equiv \operatorname{let} F \and \operatorname{de-lambda} \operatorname{in} L </math>


The sub expression may be either a lambda abstraction, or a lambda abstraction applied to a parameter.
The new lambda expression has ''S'' substituted for G. Note that ''L'' means substitution of ''S'' for ''G'' in ''L''. The function definitions has the function definition ''G = S'' added.


Two types of lift are possible.
In the above rule ''G'' is the function application that is substituted for the expression ''S''. It is defined by,
* ]
: <math>G = \operatorname{make-call}] </math>
* ]


An anonymous lift has a lift expression which is a lambda abstraction only. It is regarded as defining an anonymous function. A name must be created for the function.
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,

: <math>H \not \in \operatorname{vars} </math>
A named lift expression has a lambda abstraction applied to an expression. This lift is regarded as a named definition of a function.

==== Anonymous lift ====

An anonymous lift takes a lambda abstraction (called ''S''). For ''S'';
* Create a name for the function that will replace ''S'' (called ''V''). Make sure that the name identified by ''V'' has not been used.
* Add parameters to ''V'', for all the free variables in ''S'', to create an expression ''G'' (see ''make-call'').

The lambda lift is the substitution of the lambda abstraction ''S'' for a function application, along with the addition of a definition for the function.
: <math>\operatorname{lambda-lift} \equiv \operatorname{let} V: \operatorname{de-lambda} \operatorname{in} L </math>

The new lambda expression has ''S'' substituted for G. Note that ''L'' 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,
: <math>G = \operatorname{make-call}] </math>

where ''V'' is the function name. It must be a new variable, i.e. a name not already used in the lambda expression,
: <math>V \not \in \operatorname{vars} </math>


where <math>\operatorname{vars} </math> is a meta function that returns the set of variables used in ''E''. where <math>\operatorname{vars} </math> is a meta function that returns the set of variables used in ''E''.


{| class="wikitable mw-collapsible mw-collapsed"
For example,
|-
: <math>F = true </math>
! Example for anonymous lift.
: <math>L = \lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x)) </math>
|-
: <math>S = \lambda x.f\ (x\ x) </math>
|For example,
: <math>G = p\ f </math>
: <math>\begin{align}
F &= \operatorname{true} \\
L &= \lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x)) \\
S &= \lambda x.f\ (x\ x) \\
G &= p\ f
\end{align}</math>
: <math> \operatorname{de-lambda} \equiv p\ f\ x = f \ (x\ x) </math> : <math> \operatorname{de-lambda} \equiv p\ f\ x = f \ (x\ x) </math>
See ''de-lambda'' in ]. The result is,
gives,
: <math>\operatorname{lambda-lift} \equiv \operatorname{let} p\ f\ x = f\ (x\ x) \operatorname{in} \lambda f.(p\ f)\ (p\ f) </math>


: <math>\operatorname{lambda-lift} \equiv \operatorname{let} p\ f\ x = f\ (x\ x) \operatorname{in} \lambda f.(p\ f)\ (p\ f) </math>
==== Constructing the call ====
|}

===== 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'', The function call ''G'' is constructed by adding parameters for each variable in the free variable set (represented by ''V''), to the function ''H'',
Line 189: Line 238:
* <math>\operatorname{make-call} \equiv H </math> * <math>\operatorname{make-call} \equiv H </math>


{| class="wikitable mw-collapsible mw-collapsed"
For example,
|-
! Example of call construction.
|-
|
: <math> S = \lambda x.f\ (x\ x) </math> : <math> S = \lambda x.f\ (x\ x) </math>
: <math> \operatorname{FV}(S) = \{f\}</math> : <math> \operatorname{FV}(S) = \{f\}</math>
: <math> G \equiv \operatorname{make-call}] \equiv \operatorname{make-call} \equiv \operatorname{make-call}\ f \equiv p\ f</math> : <math> G \equiv \operatorname{make-call}] \equiv \operatorname{make-call} \equiv \operatorname{make-call}\ f \equiv p\ f</math>
|}


==== Named lift ====
==== Eta reductions to remove lambda abstractions in lifted expressions ====


The named lift is similar to the anonymous lift except that the function name ''V'' is provided.
An eta reduction is ,
: <math> \operatorname{eta-redex} = f </math> : <math>\operatorname{lambda-lift} \equiv \operatorname{let} V : \operatorname{de-lambda} \operatorname{in} L] </math>


As for the anonymous lift, the expression ''G'' is constructed from ''V'' by applying the free variables of ''S''. It is defined by,
If you assume that the eta-redex of an expression equals the expression, this can be rearranged as,
: <math>f\ x = y \iff f = \lambda x.y </math> : <math>G = \operatorname{make-call}] </math>


{| class="wikitable mw-collapsible mw-collapsed"
The de-lambda meta function applies eta-reductions to remove lambda abstractions. It is defined by,
|-
: <math> \operatorname{de-lambda} \equiv \operatorname{de-lambda} </math>
! Example for named lift.
: <math> \operatorname{de-lambda} \equiv K = E </math> if E is not a lamba abstraction
|-
|
For example,
: <math>\begin{align}
V &= x \\
E &= f\ (x\ x) \\
S &= (\lambda x.f\ (x\ x)) \\
L &= \lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x)) \\
G &= x\ f
\end{align}</math>
: <math> E = f\ (x\ x) = f\ ((x\ f)\ (x\ f)) </math>
: <math> L] = L = \lambda f.f\ ((x\ f)\ (x\ f)) </math>
: <math> \operatorname{de-lambda} \equiv x\ f\ y = f \ (y\ y) </math>
See ''de-lambda'' in ]. The result is,

gives,
: <math>\operatorname{lambda-lift} \equiv \operatorname{let} x\ f\ y = f \ (y\ y) \operatorname{in} \lambda f.(x\ f)\ (x\ f) </math>
|}

=== Lambda-lift transformation ===

A lambda lift transformation takes a lambda expression and lifts all lambda abstractions to the top of the expression. The abstractions are then translated into ], which eliminates the lambda abstractions. The result is a functional program in the form,
* <math> \operatorname{let} M \operatorname{in} N </math>

where ''M'' is a series of function definitions, and ''N'' is the expression representing the value returned.


For example, For example,
: <math> \operatorname{de-lambda} \equiv \operatorname{de-lambda} \equiv p\ f\ x = f \ (x\ x) </math> : <math> \operatorname{lambda-lift-tran} \equiv \operatorname{let} p\ f\ x = f\ (x\ x) \land q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p </math>


The ''de-let'' meta function may then be used to convert the result back into lambda calculus.
=== Candidate prefix lambda for lifting ===
: <math> \operatorname{de-let}] \equiv (\lambda p.(\lambda q.q\ p)\ \lambda p.\lambda f.(p\ f)\ (p\ f))\ \lambda f.\lambda x.f\ (x\ x) </math>


The processing of transforming the lambda expression is a series of lifts. Each lift has,
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.
* A sub expression chosen for it by the function ''lift-choice''. 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,


:<math>\begin{cases}
The rules are described below,
* <math> \operatorname{candidate-prefix-lambda} = \operatorname{lambda-prefix} </math> \operatorname{lambda-lift-tran} = \operatorname{drop-params-tran}]]\\
* <math> \text{if } \operatorname{lambda-prefix} \equiv R \text{ then } </math> \operatorname{lambda-apply} = \operatorname{lambda-process},L]\\
:: <math> \operatorname{lambda-prefix} </math> \operatorname{lambda-process} = L\\
\operatorname{lambda-process} = \operatorname{lambda-apply}]
: <math> \text{ else } </math>
\end{cases}</math>
:: <math> \operatorname{lambda-prefix}</math>
* <math> \text{if } \operatorname{lambda-prefix} \text{ then } </math>
:: <math> \operatorname{lambda-prefix} </math>
: <math> \text{ else } </math>
:: <math> \operatorname{lambda-prefix} \iff \operatorname{lambda-prefix} </math>
* <math> \neg \operatorname{lambda-prefix} </math> where x is a variable.


After the lifts are applied the lets are combined together into a single let.
=== Example ===
:<math>\begin{cases}
\operatorname{merge-let} = \operatorname{merge-let} \\
\operatorname{merge-let} = E
\end{cases}</math>


Then ] is applied to remove parameters that are not necessary in the "let" expression. The let expression allows the function definitions to refer to each other directly, whereas lambda abstractions are strictly hierarchical, and a function may not directly refer to itself.
For example the ],
: <math>\lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x)) </math>
{| class="wikitable"
|-
! !! Lambda Expression !! Function !! From !! To !! Variables
|-
| 1 || <math>\lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x)) </math> || true || <math>\lambda x.f\ (x\ x) </math> || <math>p\ f</math>|| <math>\{x, f\}</math>
|-
| 2 || <math>(\lambda f.(\lambda x.f\ (x\ x)) (\lambda x.f\ (x\ x))) </math> || <math>p\ f = \lambda x.f\ (x\ x) </math> || || || <math>\{x, f, p\}</math>
|-
| 3 || <math>\lambda f.(p\ f)\ (p\ f) </math> || <math>p\ f\ x = f\ (x\ x) </math> || <math>\lambda f.(p\ f)\ (p\ f) </math> || <math>q\ p</math> || <math>\{x, f, p\}</math>
|-
| 4 || <math>\lambda f.(p\ f)\ (p\ f) </math> || <math>p\ f\ x = f\ (x\ x) \and q\ p = \lambda f.(p\ f)\ (p\ f) </math> || || || <math>\{x, f, p, q\}</math>
|-
| 5 || <math>q\ p </math> || <math>p\ f\ x = f\ (x\ x) \and q\ p\ f = (p\ f)\ (p\ f) </math> || || || <math>\{x, f, p, q\}</math>
|}


==== Choosing the expression for lifting ====
The first sub expression to be chosen for lifting is <math>\lambda x.f\ (x\ x) </math>. This transforms the lambda expression into <math>\lambda f.(p\ f)\ (p\ f) </math> and creates the equation <math>p\ f\ x = f (x\ x) </math>.


There are two different ways that an expression may be selected for lifting. The first treats all lambda abstractions as defining anonymous functions. The second, treats lambda abstractions which are applied to a parameter as defining a function. Lambda abstractions applied to a parameter have a dual interpretation as either a let expression defining a function, or as defining an anonymous function. Both interpretations are valid.
The second sub expression to be chosen for lifting is <math>\lambda f.(p\ f)\ (p\ f)</math>. This transforms the lambda expression into <math>q\ p </math> and creates the equation <math>q\ p\ f = (p\ f)\ (p\ f) </math>.


These two predicates are needed for both definitions.
And the result is,
:<math>\operatorname{let} p\ f\ x = f\ (x\ x) \and q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p\ </math>


''lambda-free'' - An expression containing no lambda abstractions.
Because <math>p</math> is a global function, the result could also have been written,
:<math>\begin{cases}
:<math>\operatorname{let} p\ f\ x = f\ (x\ x) \and q\ f = (p\ f)\ (p\ f) \operatorname{in} q\ </math>
\operatorname{lambda-free} = \operatorname{false} \\
\operatorname{lambda-free} = \operatorname{true} \\
\operatorname{lambda-free} = \operatorname{lambda-free} \land \operatorname{lambda-free}
\end{cases}</math>


''lambda-anon'' - An anonymous function. An expression like <math>\lambda x_1.\ ...\ \lambda x_n.X </math> where X is lambda free.
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. <ref name="Optimal Lambda Lifting in Quadratic Time">
:<math>\begin{cases}
{{citation |
\operatorname{lambda-anon} = \operatorname{lambda-free} \lor \operatorname{lambda-anon} \\
title = Optimal Lambda Lifting in Quadratic Time |
\operatorname{lambda-anon} = \operatorname{false} \\
booktitle = Implementation and Application of Functional Languages - Revised Selected Papers |
\operatorname{lambda-anon} = \operatorname{false}
pages = pp 37-56 |
\end{cases}</math>
DOI = 10.1007/978-3-540-85373-2_3 |
isbn = 978-3-540-85372-5 |
}}
</ref>


===== Choosing anonymous functions only for lifting =====
===Execution===

Search for the deepest anonymous abstraction, so that when the lift is applied the function lifted will become a simple equation. This definition does not recognize a lambda abstractions with a parameter as defining a function. All lambda abstractions are regarded as defining anonymous functions.

''lift-choice'' - The first anonymous found in traversing the expression or ''none'' if there is no function.
# <math> \operatorname{lambda-anon} \to \operatorname{lift-choice} = X </math>
# <math> \operatorname{lift-choice} = \operatorname{lift-choice}</math>
# <math> \operatorname{lift-choice} \ne \operatorname{none} \to \operatorname{lift-choice} = \operatorname{lift-choice} </math>
# <math> \operatorname{lift-choice} = \operatorname{lift-choice} </math>
# <math> \operatorname{lift-choice} = \operatorname{none} </math>


For example,
Apply function to,
{| class="wikitable mw-collapsible mw-collapsed" style="white-space: nowrap;"
:<math>K</math>
|+ Lambda choice on <math> \lambda f.(\lambda x.f\ (x\ x))\ (\lambda y.f\ (y\ y)) </math> is <math> \lambda x.f\ (x\ x) </math>
{| class="wikitable"
|- |-
! Rule !! function type!! choice
! <math>\lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x))\ K </math> !! <math>\operatorname{let} p\ f\ x = f\ (x\ x) \and q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p\ \ K </math>
|- |-
| <math>(\lambda x.K\ (x\ x))\ (\lambda x.K\ (x\ x))</math>|| <math>\operatorname{let} p\ f\ x = f\ (x\ x) \and q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} p\ K\ (p\ K) </math> | 2 || || <math> \operatorname{lift-choice} </math>
|- |-
| <math>K\ ((\lambda x.K\ (x\ x))\ (\lambda x.K\ (x\ x))))\ </math>|| <math>\operatorname{let} p\ f\ x = f\ (x\ x) \and q\ p\ f = p\ f\ (p\ f) \operatorname{in} K\ (p\ K\ (p\ K)) </math> | 3 || || <math> \operatorname{lift-choice} </math>
|-
| 1 || anon || <math> \operatorname{lift-choice} </math>
|-
| || || <math> \lambda x.f\ (x\ x) </math>
|} |}


{| class="wikitable mw-collapsible mw-collapsed" style="white-space: nowrap;"
So,
* <math>(\lambda x.K\ (x\ x))\ (\lambda x.K\ (x\ x)) = K\ ((\lambda x.K\ (x\ x))\ (\lambda x.K\ (x\ x))))\ </math> |+ Lambda choice on <math> \lambda f.(p\ f)\ (p\ f) </math> is <math> \lambda f.(p\ f)\ (p\ f) </math>
|-
or
! Rule !! function type!! choice
* <math> p\ K\ (p\ K) = K\ (p\ K\ (p\ K)) </math>
|-
| 2 || anon || <math> \operatorname{lift-choice} </math>
|-
| 2 || || <math> \lambda f.(p\ f)\ (p\ f) </math>
|}


===== Choosing named and anonymous functions for lifting =====
The Y-Combinator calls its parameter (function) repeatedly on itself. The value is defined if the function has a ]. But the function will never terminate.


Search for the deepest named or anonymous function definition, so that when the lift is applied the function lifted will become a simple equation. This definition recognizes a lambda abstraction with an actual parameter as defining a function. Only lambda abstractions without an application are treated as anonymous functions.
== Lambda dropping in Lambda Calculus ==


; ''lambda-named'' : A named function. An expression like <math> (\lambda F.M)\ N </math> where M is lambda free and N is lambda free or an anonymous function.
Lambda dropping <ref>
:: <math>\begin{array}{l}
{{ cite book |
\operatorname{lambda-named} = \operatorname{lambda-free} \land \operatorname{lambda-anon} \\
author=Olivier Danvy and Ulrik P. Schultz |
\operatorname{lambda-named} = \operatorname{false} \\
title = Lambda-Dropping: Transforming Recursive Equations into Programs with Block Structure |
\operatorname{lambda-named} = \operatorname{false}
year=2001 |
\end{array}</math>
url=http://www.brics.dk/RS/99/27/BRICS-RS-99-27.pdf
}}
</ref> 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.


; ''lift-choice'' : The first anonymous or named function found in traversing the expression or ''none'' if there is no function.
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.
:# <math> \operatorname{lambda-named} \lor \operatorname{lambda-anon} \to \operatorname{lift-choice} = X </math>
:# <math> \operatorname{lift-choice} = \operatorname{lift-choice}</math>
:# <math> \operatorname{lift-choice} \ne \operatorname{none} \to \operatorname{lift-choice} = \operatorname{lift-choice} </math>
:# <math> \operatorname{lift-choice} = \operatorname{lift-choice} </math>
:# <math> \operatorname{lift-choice} = \operatorname{none} </math>


For example,
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.
{| class="wikitable mw-collapsible mw-collapsed" style="white-space: nowrap;"
|+ Lambda choice on <math> \lambda f.(\lambda x.f\ (x\ x))\ (\lambda y.f\ (y\ y)) </math> is <math> (\lambda x.f\ (x\ x))\ (\lambda y.f\ (y\ y)) </math>
|-
! Rule !! function type !! choice
|-
| 2 || || <math> \operatorname{lift-choice} </math>
|-
| 1 || named || <math> \operatorname{lift-choice} </math>
|-
| || || <math> (\lambda x.f\ (x\ x))\ (\lambda y.f\ (y\ y)) </math>
|}


{| class="wikitable mw-collapsible mw-collapsed" style="white-space: nowrap;"
In the ] 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.
|+ Lambda choice on <math> \lambda f.f\ ((x\ f)\ (x\ f)) </math> is <math>\lambda f.f\ ((x\ f)\ (x\ f)) </math>
|-
! Rule !! function type !! choice
|-
| 1 || anon || <math>\operatorname{lift-choice} </math>
|-
| || || <math>\lambda f.f\ ((x\ f)\ (x\ f)) </math>
|}


=== Rules used in Lambda dropping === === Examples ===


For example, the ],
A let expression may be converted back into a lambda expression by repeated application of the ''lambda-param'' and the ''lambda-equiv'' law,
: <math>\lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x)) </math>
is lifted as,
: <math> \operatorname{let} x\ f\ y = f\ (y\ y) \land q\ x\ f = f\ ((x\ f)\ (x\ f)) \operatorname{in} q\ x </math>
and after ],
: <math> \operatorname{let} x\ f\ y = f\ (y\ y) \land q\ f = f\ ((x\ f)\ (x\ f)) \operatorname{in} q </math>
As a lambda expression (see ]),
: <math> (\lambda x.(\lambda q.q)\ \lambda f.f\ (x\ f)\ (x\ f))\ \lambda f.\lambda y.f\ (y\ y) </math>


{| class="wikitable" {| class="wikitable mw-collapsible mw-collapsed" style="white-space: nowrap;"
|+ Lifting named and anonymous functions
|- |-
! !! Lambda Expression !! Function !! From !! To !! Variables
! Name !! Law
|- |-
| lambda-param || <math>f\ x = y \equiv f = \lambda x.y </math> | 1 || <math>\lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x)) </math> || true || <math>(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x)) </math> || <math>x\ f</math>|| <math>\{x, f\}</math>
|- |-
| 2
| lambda-equiv || <math>f \not \in FV(F) \to (\operatorname{let} f = e \and F \operatorname{in} L \equiv \operatorname{let} F \operatorname{in} \lambda f.L\ e) </math> (where f is a variable name).
|
<math>(\lambda f.(\lambda x.f\ (x\ x)) (\lambda x.f\ (x\ x))) </math>
: <math> </math>
| <math>x\ f = \lambda y.f\ (y\ y) </math>
|
|
| <math>\{x, f, p\}</math>
|-
| 3 || <math>\lambda f.f\ ((x\ f)\ (x\ f)) </math> || <math>x\ f\ y = f\ (y\ y) </math> || <math>\lambda f.f\ ((x\ f)\ (x\ f)) </math> || <math> q\ x </math> || <math>\{x, f, p\}</math>
|-
| 4 || <math>\lambda f.f\ ((x\ f)\ (x\ f)) </math> || <math> x\ f\ y = f\ (y\ y) \land q\ x = \lambda f.f\ ((x\ f)\ (x\ f)) </math> || || || <math>\{x, f, p, q\}</math>
|-
| 5 || <math> q\ x </math> || <math> x\ f\ y = f\ (y\ y) \land q\ x\ f = f\ ((x\ f)\ (x\ f)) </math> || || || <math>\{x, f, p, q\}</math>
|} |}


If lifting anonymous functions only, the Y combinator is,
=== Converting equations to lambda expressions ===
: <math>\operatorname{let} p\ f\ x = f\ (x\ x) \land q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p</math>
and after ],
: <math>\operatorname{let} p\ f\ x = f\ (x\ x) \land q\ f = (p\ f)\ (p\ f) \operatorname{in} q</math>
As a lambda expression,
: <math> (\lambda p.(\lambda q.q)\ \lambda f.(p\ f)\ (p\ f))\ \lambda f.\lambda x.f\ (x\ x) </math>


{| class="wikitable mw-collapsible mw-collapsed" style="white-space: nowrap;"
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.
|+ Lifting anonymous functions only
|-
! !! Lambda Expression !! Function !! From !! To !! Variables
|-
| 1 || <math>\lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x)) </math> || true || <math>\lambda x.f\ (x\ x) </math> || <math>p\ f</math>|| <math>\{x, f\}</math>
|-
| 2 || <math>(\lambda f.(\lambda x.f\ (x\ x)) (\lambda x.f\ (x\ x))) </math> || <math>p\ f = \lambda x.f\ (x\ x) </math> || || || <math>\{x, f, p\}</math>
|-
| 3 || <math>\lambda f.(p\ f)\ (p\ f) </math> || <math>p\ f\ x = f\ (x\ x) </math> || <math>\lambda f.(p\ f)\ (p\ f) </math> || <math>q\ p</math> || <math>\{x, f, p\}</math>
|-
| 4 || <math>\lambda f.(p\ f)\ (p\ f) </math> || <math>p\ f\ x = f\ (x\ x) \land q\ p = \lambda f.(p\ f)\ (p\ f) </math> || || || <math>\{x, f, p, q\}</math>
|-
| 5 || <math>q\ p </math> || <math>p\ f\ x = f\ (x\ x) \land q\ p\ f = (p\ f)\ (p\ f) </math> || || || <math>\{x, f, p, q\}</math>
|}


The first sub expression to be chosen for lifting is <math>\lambda x.f\ (x\ x) </math>. This transforms the lambda expression into <math>\lambda f.(p\ f)\ (p\ f) </math> and creates the equation <math>p\ f\ x = f (x\ x) </math>.
The ''lambda-lift-tran'' meta function described earlier creates "let" expressions where each function definition has no free variables. ''lambda-abstract'' needs functions with no free variables to work correctly.


The second sub expression to be chosen for lifting is <math>\lambda f.(p\ f)\ (p\ f)</math>. This transforms the lambda expression into <math>q\ p </math> and creates the equation <math>q\ p\ f = (p\ f)\ (p\ f) </math>.
For example,
: <math> \operatorname{lambda-abstract-tran} \equiv (\lambda q.(\lambda p. q\ p)\ (\lambda f.\lambda x.f\ (x\ x)))\ (\lambda p.\lambda f.(p\ f)\ (p\ f)) </math>


And the result is,
''lambda-abstract-tran'' is defined as,
* <math> \operatorname{lambda-abstract-tran} = \operatorname{lambda-convert}]] </math> : <math>\operatorname{let} p\ f\ x = f\ (x\ x) \land q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p\ </math>


Surprisingly this result is simpler than the one obtained from lifting named functions.
Lambda abstract performs three separate processing steps; pre-process, process, and convert. These steps are described below,


===Execution===
'''Pre-process''' - Split into separate lets,
* <math> \operatorname{lambda-preprocess} = \operatorname{let} A \operatorname{in} \operatorname{lambda-preprocess} </math>
* <math> \operatorname{lambda-preprocess} = \operatorname{let} A \operatorname{in} E </math>


Apply function to {{mvar|K}},
After ''lambda-preprocess'' the result for the example is,,
:<math>\begin{cases}
: <math> \operatorname{let} p\ f\ x = f\ (x\ x) \operatorname{in} \operatorname{let} q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p </math>
\lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x))\ K & \ \operatorname{let}\ p\ f\ x = f\ (x\ x) \land q\ p\ f = (p\ f)\ (p\ f) \ \operatorname{in}\ q\ p\ K \\
(\lambda x.K\ (x\ x))\ (\lambda x.K\ (x\ x)) & \ \operatorname{let}\ p\ f\ x = f\ (x\ x) \land q\ p\ f = (p\ f)\ (p\ f) \ \operatorname{in}\ p\ K\ (p\ K) \\
K\ ((\lambda x.K\ (x\ x))\ (\lambda x.K\ (x\ x))) & \ \operatorname{let}\ p\ f\ x = f\ (x\ x) \land q\ p\ f = p\ f\ (p\ f) \ \operatorname{in}\ K\ (p\ K\ (p\ K)) \\
\end{cases}</math>


So,
'''Process''' - Turn functions into lambdas,
* <math> \operatorname{lambda-process} = \operatorname{lambda-process} </math> : <math>(\lambda x.K\ (x\ x))\ (\lambda x.K\ (x\ x)) = K\ ((\lambda x.K\ (x\ x))\ (\lambda x.K\ (x\ x))))\ </math>
or
* <math> \operatorname{lambda-process} = \operatorname{let} \operatorname{abstract} \operatorname{in} \operatorname{lambda-process} </math>
: <math> p\ K\ (p\ K) = K\ (p\ K\ (p\ K)) </math>
* <math> \operatorname{lambda-process} = E </math> ..... Use this case when ''E'' is not a let expression.


The Y-Combinator calls its parameter (function) repeatedly on itself. The value is defined if the function has a ]. But the function will never terminate.
After ''lambda-process'',
: <math> \operatorname{let} p = \lambda f. \lambda x.f\ (x\ x) \operatorname{in} \operatorname{let} q = \lambda p. \lambda f.(p\ f)\ (p\ f) \operatorname{in} q\ p </math>


== Lambda dropping in lambda calculus ==
'''Convert''' - Turn lets into lambdas,
* <math> \operatorname{lambda-convert} = (\lambda F.E)\ (\operatorname{lambda-convert}) </math>
* <math> \operatorname{lambda-convert} = E </math> ..... Use this case when ''E'' is not a let expression.


Lambda dropping<ref>
Then after ''lambda-abstract-tran'',
{{ cite journal | first1 = Olivier | last1 = Danvy | first2 = Ulrik P. | last2 = Schultz
: <math> (\lambda p.(\lambda q.q\ p)\ (\lambda p. \lambda f.(p\ f)\ (p\ f)))\ (\lambda f. \lambda x.f\ (x\ x)) </math>
| title = Lambda-Dropping: Transforming Recursive Equations into Programs with Block Structure
| journal=Theoretical Computer Science |volume=248 |issue=1–2 |pages=243–287 |date=October 2000
| url=http://www.brics.dk/RS/99/27/BRICS-RS-99-27.pdf |doi=10.1016/S0304-3975(00)00054-2
| citeseerx=10.1.1.16.3943 |id=BRICS-RS-99-27
}}
</ref> is making the scope of functions smaller and using the context from the reduced scope to reduce the number of parameters to functions. Reducing the number of parameters makes functions easier to comprehend.


In the ] section, a meta function for first lifting and then converting the resulting lambda expression into recursive equation was described. The Lambda 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.
The ''abstract'' meta function removes parameters from functions using lambda abstractions. It is defined by,
: <math> \operatorname{abstract} \equiv \operatorname{abstract} </math>
: <math> \operatorname{abstract} \equiv K = E </math> if K is a variable.


Lambda dropping is performed in two steps,
For example,
* ]
: <math> \operatorname{abstract} \equiv \operatorname{abstract} \equiv \operatorname{abstract} \equiv \lambda f.\lambda x.f\ (x\ x) </math>
* ]


=== Abstraction Sinking === === Lambda drop ===


A Lambda drop is applied to an expression which is part of a program. Dropping is controlled by a set of expressions from which the drop will be excluded.
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.


:<math> \operatorname{lambda-drop-tran} = \operatorname{drop-params-tran}]]] </math> : <math> \operatorname{lambda-drop-op} = P]] </math>
where,
: ''L'' is the lambda abstraction to be dropped.
: ''P'' is the program
: ''X'' is a set of expressions to be excluded from dropping.


=== Lambda drop transformation ===
''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.

The lambda drop transformation sinks all abstractions in an expression. Sinking is excluded from expressions in a set of expressions,
:<math> \operatorname{lambda-drop-tran} = \operatorname{drop-params-tran}]] </math>
where,
: ''L'' is the expression to be transformed.
: ''X'' is a set of sub expressions to be excluded from the dropping.


''sink-tran'' sinks each abstraction, starting from the innermost, ''sink-tran'' sinks each abstraction, starting from the innermost,
:<math>\begin{cases}
: <math> \operatorname{sink-tran} = \operatorname{sink})\ \operatorname{sink-tran}]] </math>
: <math> \operatorname{sink-tran} = \lambda X.\operatorname{sink-tran} </math> \operatorname{sink-tran} = \operatorname{sink-test})\ \operatorname{sink-tran}, X] \\
: <math> \operatorname{sink-tran} = \operatorname{sink-tran}\ \operatorname{sink-tran} </math> \operatorname{sink-tran} = \lambda N.\operatorname{sink-tran} \\
: <math> \operatorname{sink-tran} = V </math> \operatorname{sink-tran} = \operatorname{sink-tran}\ \operatorname{sink-tran} \\
\operatorname{sink-tran} = V
\end{cases}</math>


=== Abstraction sinking ===
Sinking is moving a lambda abstraction inwards as far as possible such that it is still outside all references to the variable.


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.
:<math>X \not \in \operatorname{FV} \and X \not \in \operatorname{FV} \to \operatorname{sink} = G\ H </math>
:<math>X \not \in \operatorname{FV} \and X \in \operatorname{FV} \to \operatorname{sink} = G\ \operatorname{sink} </math>
:<math>X \in \operatorname{FV} \and X \not \in \operatorname{FV} \to \operatorname{sink} = (\operatorname{sink})\ H </math>
:<math>X \in \operatorname{FV} \and X \in \operatorname{FV} \to \operatorname{sink} = (\lambda X.G\ H)\ Y </math>


'''Application''' - 4 cases.
'''Abstraction''' - Only 1 case as the names of the lambda abstractions have been made distinct by ''rename''.
:<math>\begin{cases}
E \not \in \operatorname{FV} \land E \not \in \operatorname{FV} \to \operatorname{sink} = G\ H \\
E \not \in \operatorname{FV} \land E \in \operatorname{FV} \to \operatorname{sink} = \operatorname{sink-test}] \\
E \in \operatorname{FV} \land E \not \in \operatorname{FV} \to \operatorname{sink} = (\operatorname{sink-test})\ H \\
E \in \operatorname{FV} \land E \in \operatorname{FV} \to \operatorname{sink} = (\lambda E.G\ H)\ Y \end{cases}</math>


'''Abstraction'''. Use renaming to insure that the variable names are all distinct.
:<math>X \ne V \to \operatorname{sink} = \lambda V.\operatorname{sink} </math>
:<math>V \ne W \to \operatorname{sink} = \lambda W.\operatorname{sink-test} </math>


'''Variable''' - 2 cases. '''Variable''' - 2 cases.
:<math>X \ne V \to \operatorname{sink} = V </math> :<math>E \ne V \to \operatorname{sink} = V </math>
:<math>X = V \to \operatorname{sink} = Y </math> :<math>E = V \to \operatorname{sink} = Y </math>


Sink test excludes expressions from dropping,
For the example above, sinking,
: <math> \operatorname{sink-tran} </math> : <math> L \in X \to \operatorname{sink-test} = L </math>
: <math> = \operatorname{sink})\ (\lambda f.\lambda x.f\ (x\ x))] </math> : <math> L \not \in X \to \operatorname{sink-test} = \operatorname{sink} </math>
: <math> = \operatorname{sink})\ (\lambda f.\lambda x.f\ (x\ x))] </math>
: <math> = \operatorname{sink} </math>
: <math> = (\lambda p.\lambda f.(p\ f)\ (p\ f)))\ \operatorname{sink} </math>
: <math> = (\lambda p.\lambda f.(p\ f)\ (p\ f))\ (\lambda f.\lambda x.f\ (x\ x)) </math>


==== Example ====
Sinking a second time,
: <math> \operatorname{sink-tran} </math>
: <math> = \operatorname{sink} </math>
: <math> = \lambda f.\operatorname{sink} </math>
: <math> = \lambda f.(\lambda p.(p\ f)\ (p\ f))\ (\lambda f.\lambda x.f\ (x\ x)) </math>


{| class="wikitable mw-collapsible mw-collapsed"
=== Parameter Dropping ===
|-
! Example of sinking
|-
|
For example,
{| class="wikitable"
|-
! Rule !! Expression
|-
| ''de-let''
| <math> \operatorname{sink-tran}] </math>
|-
| ''sink-tran''
| <math> \operatorname{sink-tran} </math>
|-
| Application
|
{| class="wikitable mw-collapsible mw-collapsed"
|-
! <math> \operatorname{sink})\ (\lambda f.\lambda x.f\ (x\ x))] </math>
|-
| <math> \operatorname{sink} </math>
|-
| <math>E \in \operatorname{FV} \land E \not \in \operatorname{FV} \to \operatorname{sink} </math>
|-
| <math> E = q, G = q, H = p, Y = (\lambda p. \lambda f.(p\ f)\ (p\ f)), X = \{\} </math>
|-
| <math> (\operatorname{sink})\ H </math>
|-
| <math> (\operatorname{sink})\ p </math>
|}
|-
| Variable
|
{| class="wikitable mw-collapsible mw-collapsed"
|-
! <math> \operatorname{sink}\ p)\ (\lambda f.\lambda x.f\ (x\ x))] </math>
|-
| <math> \operatorname{sink} </math>
|-
| <math>E = V \to \operatorname{sink} </math>
|-
| <math> E = q, V = q, Y = (\lambda p. \lambda f.(p\ f)\ (p\ f)), X = \{\} </math>
|-
| <math> Y </math>
|-

| <math> (\lambda p. \lambda f.(p\ f)\ (p\ f)) </math>
|}
|-
| Application
|
{| class="wikitable mw-collapsible mw-collapsed"
|-
! <math> \operatorname{sink} </math>
|-
| <math>E \not \in \operatorname{FV} \land E \in \operatorname{FV} \to \operatorname{sink} </math>
|-
| <math> E = p, G = (\lambda p.\lambda f.(p\ f)\ (p\ f)), H = p, Y = (\lambda f.\lambda x.f\ (x\ x)) </math>
|-
| <math>\operatorname{sink}] </math>
|}
|-
|
|
|-
| Variable
|
{| class="wikitable mw-collapsible mw-collapsed"
|-
! <math>\operatorname{sink}] </math>
|-
| <math>\operatorname{sink} </math>
|-
| <math>E = V \to \operatorname{sink} </math>
|-
| <math> E = p, V = p, Y = (\lambda f.\lambda x.f\ (x\ x)), X = \{\} </math>
|-
| <math> Y </math>
|-
| <math> (\lambda f.\lambda x.f\ (x\ x)) </math>
|}
|-
| Abstraction
|
{| class="wikitable mw-collapsible mw-collapsed"
|-
! <math> \operatorname{sink} </math>
|-
|<math> V \ne W \to \operatorname{sink}</math>
|-
| <math> V = p, W = f, E = (p\ f)\ (p\ f), Y = (\lambda f.\lambda x.f\ (x\ x)) </math>
|-
| <math> \lambda W.\operatorname{sink} </math>
|}
|-
| Application
|
{| class="wikitable mw-collapsible mw-collapsed"
|-
! <math> \lambda f.\operatorname{sink} </math>
|-
| <math> \operatorname{sink} </math>
|-
| <math>E \in \operatorname{FV} \land E \in \operatorname{FV} \to \operatorname{sink} </math>
|-
| <math> E = p, G = (p\ f), H = (p\ f), Y = (\lambda f.\lambda x.f\ (x\ x)) </math>
|-
| <math> (\lambda E.G\ H)\ Y </math>
|-
| <math> (\lambda p.(p\ f)\ (p\ f))\ (\lambda f.\lambda x.f\ (x\ x)) </math>
|}
|-
|
| <math> \lambda f.(\lambda p.(p\ f)\ (p\ f))\ (\lambda f.\lambda x.f\ (x\ x)) </math>
|}
|}

=== 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. 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 are 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. 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, For example, consider,
:<math> (\lambda g.k\ (\lambda n.(g\ m\ p\ n)\ (g\ q\ p\ n))\ (f\ x))\ \lambda x.\lambda o.\lambda y.o\ x\ y </math> : <math> \lambda m,p,q.(\lambda g.\lambda n.(n\ (g\ m\ p\ n)\ (g\ q\ p\ n)))\ \lambda x.\lambda o.\lambda y.o\ x\ y </math>


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. 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, The result of dropping the parameter is,
:<math> \operatorname{drop-params-tran} </math> :<math> \operatorname{drop-params-tran}[\lambda m,p,q.(\lambda g.\lambda n.n\ (g\ m\ p\ n)\ (g\ q\ p\ n))\ \lambda x.\lambda o.\lambda y.o\ x\ y </math>
::::::<math> \equiv (\lambda g.k\ (\lambda n.(g\ m\ n)\ (g\ q\ n))\ (f\ x))\ \lambda x.\lambda y.p\ x\ y </math> ::::::<math> \equiv \lambda m,p,q.(\lambda g.\lambda n.n\ (g\ m\ n)\ (g\ q\ n))\ \lambda x.\lambda y.p\ x\ y </math>


For the main example, For the main example,
Line 424: Line 698:
:<math>\operatorname{drop-params-tran} \equiv (\operatorname{drop-params}, ]) </math> :<math>\operatorname{drop-params-tran} \equiv (\operatorname{drop-params}, ]) </math>
where, where,
:<math> \operatorname{build-param-lists} </math> :<math> \operatorname{build-param-list} </math>


==== Build parameter lists ==== ==== 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 each abstraction that defines a function, build the information required to make decisions on dropping names. This information describes 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, For example, in,
: <math> (\lambda g.k\ (\lambda n.(g\ m\ p\ n)\ (g\ q\ p\ n))\ (f\ x))\ \lambda x.\lambda o.\lambda y.o\ x\ y </math> : <math> \lambda m,p,q.(\lambda g.\lambda n.(n\ (g\ m\ p\ n)\ (g\ q\ p\ n)))\ \lambda x.\lambda o.\lambda y.o\ x\ y </math>


the parameters to the function ''g'' are, the parameters to the function ''g'' are,
Line 439: Line 713:
! Formal Parameter !! All Same Value !! Actual parameter expression ! Formal Parameter !! All Same Value !! Actual parameter expression
|- |-
| ''x'' || false || _ | ''x'' || {{no2|false}} || _
|- |-
| ''o'' || true || ''p'' | ''o'' || {{yes2|true}} || ''p''
|- |-
| ''y'' || true || ''n'' | ''y'' || {{yes2|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; Each abstraction is renamed with a unique name, and the parameter list is associated with the name of the abstraction. For example, ''g'' there is parameter list.
: <math> D = , , ] </math> : <math> D = , , ] </math>


''build-param-lists'' builds all the lists for an expression, by traversing the expression. ''build-param-lists'' builds all the lists for an expression, by traversing the expression. It has four parameters;
* The lambda expression being analyzed.
* The table parameter lists for names.
* The table of values for parameters.
* The returned parameter list, which is used internally by the


'''Abstraction''' - A lambda expression of the form <math> (\lambda N.S)\ L </math> is analyzed to extract the names of parameters for the function. '''Abstraction''' - A lambda expression of the form <math> (\lambda N.S)\ L </math> is analyzed to extract the names of parameters for the function.


:<math>\begin{cases}
: <math> \operatorname{build-param-lists} \equiv \operatorname{build-param-lists} \and \operatorname{build-list}] </math>
\operatorname{build-param-lists} \equiv \operatorname{build-param-lists} \land \operatorname{build-list}] \\
\operatorname{build-param-lists} \equiv \operatorname{build-param-lists}
\end{cases}</math>


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 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


:<math>\begin{cases}
: <math> \operatorname{build-list}::L] \equiv \operatorname{param-list} </math>
: <math> \operatorname{param-list}] \equiv \operatorname{build-param-lists} </math> \operatorname{build-list}::L] \equiv \operatorname{build-list} \\
\operatorname{build-list}] \equiv \operatorname{build-param-lists}
\end{cases}</math>


'''Variable''' - A call to a function. '''Variable''' - A call to a function.


: <math> \operatorname{build-param-lists}] </math> : <math> \operatorname{build-param-lists}] </math>


For a function name or parameter start populating actual parameter list by outputting the parameter list for this name. 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. '''Application''' - An application (function call) is processed to extract actual parameter details.


: <math> \operatorname{build-param-lists} \equiv \operatorname{build-param-lists} \and \operatorname{build-param-lists} </math> : <math> \operatorname{build-param-lists} \equiv \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
::::::::<math> \and (T = ::R \and S \implies \operatorname{equate} \and V = A \and K = D \or T = \and R = ) </math> :: <math> \land T = ::R \land (S \implies (\operatorname{equate} \land V = A)) \land D = K </math>


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. 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.


:<math>\begin{cases}
: <math> \operatorname{equate} \equiv A = V \or A = N </math> ... if N is a variable.
: <math> \operatorname{equate} \equiv A = E </math> ... otherwise. \operatorname{equate} \equiv A = N \lor (\operatorname{def}] \land A = V) & \text{if }N\text{ is a variable.} \\
\operatorname{equate} \equiv A = E & \text{otherwise.}
\end{cases}</math>


The above logic is quite subtle in the way that it works. 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.
The logic for ''equate'' is used in this more difficult example,
: <math> \lambda f.(\lambda p.f\ (p\ p\ f))\ (\lambda q.\lambda x.x\ (q\ q\ x)) </math>
has the parameter x dropped to become,
: <math> \lambda f.(\lambda q.f\ (q\ q))\ (\lambda q.f\ (q\ q)) </math>


: <math> \operatorname{ask} \equiv S \in \{ X : X = S \} </math>
{| class="wikitable"

Similarly, ''def'' uses set theory to query if a variable has been given a value;
: <math> \operatorname{def} \equiv |\{X : X = F\}| </math>

'''Let''' - Let expression.

:<math> \operatorname{build-param-list} \equiv \operatorname{build-param-list} \land \operatorname{build-param-list} </math>

'''And''' - For use in "let".

: <math> \operatorname{build-param-lists} \equiv \operatorname{build-param-lists} \land \operatorname{build-param-lists}</math>

===== Examples =====

For example, building the parameter lists for,
: <math> \lambda m,p,q.(\lambda g.\lambda n.(n\ (g\ m\ p\ n)\ (g\ q\ p\ n)))\ \lambda x.\lambda o.\lambda y.o\ x\ y </math>
gives,
: <math> D = , , ] </math>
and the parameter o is dropped to give,
: <math> \lambda m,p,q.(\lambda g.\lambda n.(n\ (g\ m\ n)\ (g\ q\ n)))\ \lambda x.\lambda y.p\ x\ y </math>

{| class="wikitable mw-collapsible mw-collapsed"
|- |-
! Build parameter list for <math> \lambda m,p,q.(\lambda g.\lambda n.(n\ (g\ m\ p\ n)\ (g\ q\ p\ n)))\ \lambda x.\lambda o.\lambda y.o\ x\ y </math>
! !! function !! param 1 !! param 2
|- |-
! Build parameter list example
| Abstract || p || p || x
|- |-
|
| Application 1 || p || p || f
{| class="wikitable mw-collapsible mw-collapsed"
|+ <math> \operatorname{build-param-list} </math>
|- |-
! Rule !!Expression
| Application 2 || q || q || x
|-
| Abstraction
| <math> \operatorname{build-param-list} </math>
|-
| Abstraction
| <math> \operatorname{build-param-list} </math>
|-
|
| <math> \operatorname{build-param-lists} \land \operatorname{build-list}] </math>
|} |}


{| class="wikitable mw-collapsible mw-collapsed"
''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, <math> A = V </math>. The condition <math> K = D </math> supports the functions ''q'' and ''p'' sharing the same parameter list, which is also needed in this example.
|+ <math> \operatorname{build-list}] </math>
|-
! Rule !!Expression
|-
| Add param
|
<math> \operatorname{build-list}] \land D = L_1 </math>
|-
| Add param
|
<math> \operatorname{build-list} \land D = ::L_1 </math>
|-
| Add param
|
<math> \operatorname{build-list} \land D = ::::L_2 </math>
|-
| End list
| <math> \operatorname{build-list} \land D = ::::::L_3 </math>
|-
|
| <math> \operatorname{build-param-lists}] \land D = :::::: </math>
|}


{| class="wikitable mw-collapsible mw-collapsed"
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.
|+ <math> \operatorname{build-param-lists} </math>
|-
! Rule !! Expression
|-
| Application
| <math> \operatorname{build-param-lists} </math>
|-
| Application
|
<math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land ((T_1 = ::R </math>
: <math> \land (S_1 \implies (\operatorname{equate} \land V = g\ q\ p\ n)) \land D = K_1) </math>
|-
| Variable
|
<math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land ((T_2 = ::::R </math>
: <math> \land (S_1 \implies (\operatorname{equate} \land V = g\ q\ p\ n)) \land D = K_1) </math>
: <math> \land (S_2 \implies (\operatorname{equate} \land V = g\ m\ p\ n)) \land D = K_2) </math>
|-
| Variable
|
<math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land ((D = ::::R </math>
: <math> \land (S_1 \implies (\operatorname{equate} \land V = g\ q\ p\ n)) \land D = K_1) </math>
: <math> \land (S_2 \implies (\operatorname{equate} \land V = g\ m\ p\ n)) \land D = K_2) </math>
|}


Gives,
: <math> \operatorname{ask} \equiv T \in \{ X : X = S \} </math>
: <math> D = ::::R </math>

{| class="wikitable mw-collapsible mw-collapsed"
|+ <math> \operatorname{build-param-lists} </math>
|-
! Rule !! Expression
|-
| application
|
<math> \operatorname{build-param-lists} </math>
|-
|
|
<math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land ((T_3 = ::K_2 </math>
: <math> \land (S_3 \implies (\operatorname{equate} \land V = n)) \land D = D) </math>
|-
| application, Variable
|
<math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land T_4 = ::::K_2 </math>
: <math> \land (S_3 \implies (\operatorname{equate} \land V = n)) \land D = D) </math>
: <math> \land (S_4 \implies (\operatorname{equate} \land V = p)) \land D = D </math>
|-
| application, Variable
|
<math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land T_5 = ::::::K_2 </math>
: <math> \land (S_3 \implies (\operatorname{equate} \land V = n)) \land D = D) </math>
: <math> \land (S_4 \implies (\operatorname{equate} \land V = p)) \land D = D </math>
: <math> \land (S_5 \implies (\operatorname{equate} \land V = m)) \land D = D </math>
|-
| Variable
|
<math> D = ::::::K_2 </math>
: <math> \land (S_3 \implies (\operatorname{equate} \land V = n)) \land D = D) </math>
: <math> \land (S_4 \implies (\operatorname{equate} \land V = p)) \land D = D </math>
: <math> \land (S_5 \implies (\operatorname{equate} \land V = m)) \land D = D </math>
|}

{| class="wikitable mw-collapsible mw-collapsed"
|+ <math> \operatorname{build-param-lists} </math>
|-
! Rule !! Expression
|-
| application
|
<math> \operatorname{build-param-lists} </math>
|-
|
|
<math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land ((T_6 = ::K_1 </math>
: <math> \land (S_6 \implies (\operatorname{equate} \land V = n)) \land D = D) </math>
|-
| application, Variable
|
<math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land T_7 = ::::K_1 </math>
: <math> \land (S_6 \implies (\operatorname{equate} \land V = n)) \land D = D) </math>
: <math> \land (S_7 \implies (\operatorname{equate} \land V = p)) \land D = D </math>
|-
| application, Variable
|
<math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land T_8 = ::::::K_1 </math>
: <math> \land (S_6 \implies (\operatorname{equate} \land V = n)) \land D = D) </math>
: <math> \land (S_7 \implies (\operatorname{equate} \land V = p)) \land D = D </math>
: <math> \land (S_8 \implies (\operatorname{equate} \land V = q)) \land D = D </math>
|-
| Variable
|
<math> D = ::::::K_1 </math>
: <math> \land (S_6 \implies (\operatorname{equate} \land V = n)) \land D = D) </math>
: <math> \land (S_7 \implies (\operatorname{equate} \land V = p)) \land D = D </math>
: <math> \land (S_8 \implies (\operatorname{equate} \land V = q)) \land D = D </math>
|}

As there are no definitions for, <math>V, V, V, V </math>, then equate can be simplified to,
: <math> \operatorname{equate} \equiv A = N \lor (\operatorname{def}] \land A = V) \equiv A = N </math>

By removing expressions not needed,
<math> D = ::::::K_2 </math>
: <math> \land S_3 \implies A_3 = n </math>
: <math> \land S_4 \implies A_4 = p </math>
: <math> \land S_5 \implies A_5 = m </math>
<math> D = ::::::K_1 </math>
: <math> \land S_6 \implies A_6 = n </math>
: <math> \land S_7 \implies A_7 = p </math>
: <math> \land S_8 \implies A_8 = q </math>

By comparing the two expressions for <math> D </math>, get,
: <math> S_5 = S_8, A_5 = A_8, S_4 = S_7, A_4 = A_7, S_3 = S_6, A_3 = A_6 </math>

If <math>S_3</math> is true;
: <math> n = A_3 = A_6 = n </math>
If <math>S_3</math> is false there is no implication. So <math>S_3 = \_</math> which means it may be true or false.

If <math>S_4</math> is true;
: <math> p = A_4 = A_7 = p </math>

If <math>S_5</math> is true;
: <math> m = A_5 = A_8 = q </math>
So <math>S_5</math> is false.

The result is,
<math> D = ::::::\_ </math>

{| class="wikitable mw-collapsible mw-collapsed"
|+ <math> \operatorname{build-param-lists} </math>
|-
! Rule !! Expression
|-
| application
| <math> \operatorname{build-param-lists} </math>
|-
| application
|
<math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land T_9 = ::L </math>
: <math> \land (S_9 \implies (\operatorname{equate} \land V = A_9) \land K_9 = D </math>
|-
| variable
|
<math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land T_{10} = ::::L </math>
: <math> \land (S_9 \implies (\operatorname{equate} \land V = A_9) \land K_9 = D </math>
: <math> \land (S_{10} \implies (\operatorname{equate} \land V = A_{10}) \land K_{10} = D </math>
|-
|
|
: <math> \land D = ::::L </math>
: <math> \land (S_9 \implies (\operatorname{equate} \land V = A_9) \land K_9 = D </math>
: <math> \land (S_{10} \implies (\operatorname{equate} \land V = A_{10}) \land K_{10} = D </math>
|}

By similar arguments as used above get,
: <math> D= ::::\_ </math>

and from previously,
: <math> D = , , ] </math>
: <math> D = , ]</math>
: <math> D = \_ </math>
: <math> D = \_ </math>
: <math> D = \_ </math>
|}

Another example is,
: <math> \lambda f.((\lambda p.f\ (p\ p\ f))\ (\lambda q.\lambda x.x\ (q\ q\ x)) </math>
Here x is equal to f. The parameter list mapping is,
: <math> D = , ] </math>
and the parameter x is dropped to give,
: <math> \lambda f.((\lambda q.f\ (q\ q))\ (\lambda q.f\ (q\ q)) </math>

{| class="wikitable mw-collapsible mw-collapsed"
|-
! Build parameter list for <math> \lambda f.((\lambda p.f\ (p\ p\ f))\ (\lambda q.\lambda x.x\ (q\ q\ x)) </math>
|-
|
The logic in ''equate'' is used in this more difficult example.

{| class="wikitable mw-collapsible mw-collapsed"
|+ <math> \operatorname{build-param-list} </math>
|-
! Rule !!Expression
|-
| Abstraction
| <math> \operatorname{build-param-list} </math>
|-
| Abstraction
| <math> \operatorname{build-param-list} </math>
|-
|
| <math> \operatorname{build-param-lists} \land \operatorname{build-list}] </math>
|-
|
| <math> \operatorname{build-param-lists} \land \operatorname{build-list}] </math>
|}

{| class="wikitable mw-collapsible mw-collapsed"
|+ <math> \operatorname{build-list}] </math>
|-
! Rule !! Expression
|-
| Add param
| <math> \operatorname{build-list}] \land D = L_1</math>
|-
| Add param
| <math> \operatorname{build-list} \land D = ::L_2</math>
|-
| End list
| <math> \operatorname{build-list} \land D = ::::L_3</math>
|-
|
| <math> \operatorname{build-param-lists}] \land D = ::::</math>
|}

{| class="wikitable mw-collapsible mw-collapsed"
|+ <math> \operatorname{build-param-lists} </math>
|-
! Rule !!Expression
|-
| Abstraction
| <math> \operatorname{build-param-lists} </math>
|-
| Application
| <math> \operatorname{build-param-lists} </math>
|-
| Name
| <math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land T_2 = ::::\_ </math>
:<math> \land (S_2 \implies (\operatorname{equate} \land V = A_2)) \land D = K_2 </math>
|-
| Name
| <math> \operatorname{build-param-lists} </math>
<math> \land D = ::::\_ </math>
: <math> \land (S_2 \implies (\operatorname{equate} \land V = A_2)) \land D = K_2 </math>
|-
| Name
| <math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land T_3 = ::K_2 </math>
: <math> \land (S_3 \implies (\operatorname{equate} \land V = A_3)) \land D = K_3 </math>
|-
| Application
| <math> \operatorname{build-param-lists} </math>
: <math> \land T_3 = ::K_2 </math>
: <math> \land (S_2 \implies (\operatorname{equate} \land V = A_2)) \land D = K_2 </math>
: <math> \land (S_3 \implies (\operatorname{equate} \land V = A_3)) \land D = D </math>
|-
| Name
| <math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land T_4 = ::::K_2 </math>
: <math> \land (S_3 \implies (\operatorname{equate} \land V = A_3)) \land D = D </math>
: <math> \land (S_4 \implies (\operatorname{equate} \land V = A_4)) \land D = K_4 </math>
|-
|
| <math> D = ::::K_2 </math>
: <math> \land (S_3 \implies (\operatorname{equate} \land V = A_3)) \land D = D </math>
: <math> \land (S_4 \implies (\operatorname{equate} \land V = A_4)) \land D = D </math>
|}

{| class="wikitable mw-collapsible mw-collapsed"
|+ <math> \operatorname{build-param-lists} </math>
|-
! Rule !!Expression
|-
| Abstraction
| <math> \operatorname{build-param-lists} </math>
|-
| Application
| <math> \operatorname{build-param-lists} </math>
|-
| Name
| <math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land T_5 = ::\_ </math>
: <math> \land (S_5 \implies (\operatorname{equate} \land V = A_5)) \land D = K_5 </math>
|-
| Name
| <math> \operatorname{build-param-lists} </math>
: <math> \land D = ::\_ </math>
: <math> \land (S_5 \implies (\operatorname{equate} \land V = A_5)) \land D = K_5 </math>
|-
| Name
| <math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land T_6 = ::K_5 </math>
: <math> \land (S_6 \implies (\operatorname{equate} \land V = A_6)) \land D = K_6 </math>
|-
| Application
| <math> \operatorname{build-param-lists} </math>
: <math> \land T_6 = ::K_5 </math>
: <math> \land (S_6 \implies (\operatorname{equate} \land V = A_6)) \land D = D </math>
|-
| Name
| <math> \operatorname{build-param-lists} \land \operatorname{build-param-lists} </math>
: <math> \land T_7 = ::::K_5 </math>
: <math> \land (S_6 \implies (\operatorname{equate} \land V = A_6)) \land D = D </math>
: <math> \land (S_7 \implies (\operatorname{equate} \land V = A_7)) \land D = K_7 </math>
|-
| Name
| <math> \operatorname{build-param-lists} </math>
: <math> \land D = ::::K_5 </math>
: <math> \land (S_6 \implies (\operatorname{equate} \land V = A_6)) \land D = D </math>
: <math> \land (S_7 \implies (\operatorname{equate} \land V = A_7)) \land D = D </math>
|}

After collecting the results together,
: <math> D = ::::L_3</math>
: <math> D = ::::K_2 </math>
: <math> \land (S_3 \implies (\operatorname{equate} \land V = A_3)) \land D = D </math>
: <math> \land (S_4 \implies (\operatorname{equate} \land V = A_4)) \land D = D </math>
: <math> D = ::::K_5 </math>
: <math> (S_6 \implies (\operatorname{equate} \land V = A_6)) \land D = D </math>
: <math> (S_7 \implies (\operatorname{equate} \land V = A_7)) \land D = D </math>

From the two definitions for <math> D </math>;
: <math> F_4 = q </math>
: <math> F_3 = x </math>
so
: <math> D = ::::K_2 </math>
: <math> (S_3 \implies (\operatorname{equate} \land V = A_3)) \land D = D </math>
: <math> (S_4 \implies (\operatorname{equate} \land V = A_4)) \land D = D </math>

Using <math> D = D </math> and
: <math> D = ::::K_5 </math>
: <math> (S_6 \implies (\operatorname{equate} \land V = A_6)) \land D = D </math>
: <math> (S_7 \implies (\operatorname{equate} \land V = A_7)) \land D = D </math>

by comparing with the above,
: <math> F_7 = q, F_6 = x, A_3 = A_6, A_4 = A_7, S_3 = S_6, S_4 = S_7 </math>
so,
: <math> V = A_3 </math>
: <math> V = A_4 </math>
in,
: <math> S_3 \implies A_3 = f </math>
: <math> S_3 \implies (A_3 = x \lor A_3 = v) </math>
reduces to,
: <math> S_3 \implies A_3 = f </math>
also,
: <math> S_4 \implies A_4 = p </math>
: <math> S_4 \implies (A_4 = q \lor A_4 = v) </math>
reduces to,
: <math> S_4 \implies A_4 = p </math>

So the parameter list for p is effectively;
: <math> D = ::::\_ </math>
|}


==== Drop parameters ==== ==== Drop parameters ====


Use the information obtained by ] to drop actual parameters that are no longer required. ''drop-params'' has the parameters,
'''Abstraction''' - Two cases; abstraction with application, abstraction aloe
* The lambda expression in which the parameters are to be dropped.
* The mapping of variable names to parameter lists (built in Build parameter lists).
* The set of variables free in the lambda expression.
* The returned parameter list. A parameter used internally in the algorithm.


'''Abstraction'''
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.

: <math> \operatorname{drop-params} \equiv (\lambda N.\operatorname{drop-params})\ \operatorname{drop-formal}, L, F, ] </math>
: <math> \operatorname{drop-params} \equiv (\lambda N.\operatorname{drop-params})\ \operatorname{drop-formal}, L, F] </math>
where, where,
: <math> F = FV((\lambda N.S)\ L) </math> : <math> F = FV </math>


: <math> \operatorname{drop-params} \equiv (\lambda N.\operatorname{drop-params}) </math>
Abstraction alone. Use this case only if there is no application. Drop parameters in the body of the abstraction based on the parameter lists.
where,
: <math> \operatorname{drop-params} \equiv (\lambda N.\operatorname{drop-params}) </math>
: <math> F = FV </math>


'''Variable'''. '''Variable'''


: <math> \operatorname{drop-params}] \equiv N </math> : <math> \operatorname{drop-params}] \equiv N </math>


For a function name or parameter start populating actual parameter list by outputting the parameter list for this name.
'''Application''' - Two cases; parameter dropped or not dropped. Use this case only when the function expression ''E'' is not an abstraction.


'''Application''' - An application (function call) is processed to extract
: <math> (\operatorname{ask} \and FV \subset V) \to \operatorname{drop-params} \equiv \operatorname{drop-params}::R, T] </math>

: <math> \neg (\operatorname{ask} \and FV \subset V) \to \operatorname{drop-params} \equiv \operatorname{drop-params}::R, T]\ \operatorname{drop-params} </math>
: <math> (\operatorname{def} \land \operatorname{ask} \land FV \subset V) \to \operatorname{drop-params} \equiv \operatorname{drop-params}::R] </math>
: <math> \neg (\operatorname{def} \land \operatorname{ask} \land FV \subset V) \to \operatorname{drop-params} \equiv \operatorname{drop-params}::R]\ \operatorname{drop-params} </math>

'''Let''' - Let expression.

:<math>\operatorname{drop-params} \equiv \operatorname{let} V: \operatorname{drop-params}, ] \operatorname{in} \operatorname{drop-params}, ] </math>

'''And''' - For use in "let".

: <math> \operatorname{drop-params} \equiv \operatorname{drop-params} \land \operatorname{drop-params}</math>

{| class="wikitable mw-collapsible mw-collapsed"
|-
! Drop parameters from applications
|-
|
{| class="wikitable mw-collapsible"
|+ <math> \lambda g.\lambda n.n\ (g\ m\ p\ n)\ (g\ q\ p\ n) </math>
|-
! Condition !! Expression
|-
|
| <math> \operatorname{drop-param} </math>
|-
|
| <math> \lambda g.\operatorname{drop-param} </math>
|-
| <math> \neg (\operatorname{def} \land ...) </math>
| <math> \lambda g.\lambda n.\operatorname{drop-param}::\_]\ \operatorname{drop-param} </math>
|-
| <math> \neg (\operatorname{def} \land ...) </math>
| <math> \lambda g.\lambda n.\operatorname{drop-param}::::\_]\ \operatorname{drop-param} \ \operatorname{drop-param} </math>
|-
| <math> D = ::::\_]</math>
| <math> \lambda g.\lambda n.n\ \operatorname{drop-param} \ \operatorname{drop-param} </math>
|-
|
|}

From the results of building parameter lists;
: <math> D = , ]</math>
so,
: <math> F_1 = \_ </math>
: <math> F_2 = \_ </math>
so,
: <math> \operatorname{def} = \operatorname{false} </math>
: <math> \operatorname{def} = \operatorname{false} </math>

{| class="wikitable mw-collapsible"
|+ <math> \operatorname{drop-param} </math>
|-
! Condition !! Expanded !! Expression
|-
| <math> V = \{p, q, m\} </math>
|
| <math> \operatorname{drop-param} </math>
|-
| <math> FV(A_1) \not \subset \{p, q, m\} </math>
| <math> n \not \subset \{p, q, m\} </math>
| <math> \operatorname{drop-params}::\_]\ \operatorname{drop-params} </math>
|-
| <math> \operatorname{def} \land \operatorname{ask} \land FV \subset V </math>
| <math> \operatorname{def} \land \operatorname{ask} \land FV \subset \{p, q, m\} </math>
| <math> \operatorname{drop-params}::::\_]\ \operatorname{drop-params} </math>
|-
| <math> \neg \operatorname{ask} </math>
| <math> \neg \operatorname{ask} </math>
| <math> \operatorname{drop-params}::::::\_]\ \operatorname{drop-params}\ \operatorname{drop-params} </math>
|-
|
<math> D = , , ] </math>
<math> = ::::::\_] </math>
|
<math> F_3 = x, S_3 = \operatorname{false}, A_3 = \_ </math>
<math> F_2 = o, S_2 = \_, A_2 = p </math>
<math> F_1 = y, S_1 = \_, A_1 = n </math>
|
<math> g\ m\ n </math>
|}

{| class="wikitable mw-collapsible"
|+ <math> \operatorname{drop-param} </math>
|-
! Condition !! Expanded !! Expression
|-
| V = \{p, q, m\}
|
| <math> \operatorname{drop-param} </math>
|-
| <math> FV(A_4) \not\subset V </math>
| <math> n \not\subset \{p, q, m\} </math>
| <math> \operatorname{drop-params}::\_]\ \operatorname{drop-params} </math>
|-
| <math> \operatorname{def} \land \operatorname{ask} \land FV \subset V </math>
| <math> \operatorname{def} \land \operatorname{ask} \land p \subset \{p, q, m\}) </math>
| <math> \operatorname{drop-params}::::\_]\ \operatorname{drop-params} </math>
|-
| <math> \neg \operatorname{ask} </math>
| <math> \neg \operatorname{ask} </math>
| <math> \operatorname{drop-params}::::::\_]\ \operatorname{drop-params}\ \operatorname{drop-params} </math>
|-
|
<math> D = , , ] </math>
<math> = ::::::\_] </math>
|
<math> F_6 = x, S_6 = \operatorname{false}, A_6 = \_ </math>
<math> F_5 = o, S_5 = \_, A_5 = p </math>
<math> F_4 = y, S_4 = \_, A_4 = n </math>
|
<math> g\ q\ n </math>
|}
|}


===== Drop formal parameters ===== ===== Drop formal parameters =====


''drop-formal'' removes formal parameters, based on the contents of the parameter lists. Its parameters are, ''drop-formal'' removes formal parameters, based on the contents of the drop lists. Its parameters are,
* The parameter list, * The drop list,
* The function definition (lambda abstraction). * The function definition (lambda abstraction).
* The free variables from the function definition. * The free variables from the function definition.


''drop-formal'' has 2 cases; parameter dropped, parameter not dropped. ''drop-formal'' is defined as,
# <math> (\operatorname{ask} \and FV \subset V) \to \operatorname{drop-formal}::Z, \lambda F.Y, V] \equiv \operatorname{drop-formal}::Z, Y, V] </math> # <math> (\operatorname{ask} \land FV \subset V) \to \operatorname{drop-formal}::Z, \lambda F.Y, V] \equiv \operatorname{drop-formal}::Z, Y, L] </math>
# <math> \neg (\operatorname{ask} \and FV \subset V) \to \operatorname{drop-formal}::Z, \lambda F.Y, V] \equiv \lambda F.\operatorname{drop-formal}::Z, Y, V] </math> # <math> \neg (\operatorname{ask} \land FV \subset V) \to \operatorname{drop-formal}::Z, \lambda F.Y, V] \equiv \lambda F.\operatorname{drop-formal}::Z, Y, V] </math>
# <math> \operatorname{drop-formal} \equiv Y </math> # <math> \operatorname{drop-formal} \equiv Y </math>


Which can be explained as, 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. # 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 its value.
# else do not drop the parameter. # else do not drop the parameter.
# else return the body of the function. # else return the body of the function.


{| class="wikitable mw-collapsible mw-collapsed"
For example,
: <math> Z = , , ] </math>
: <math> V = \{ k, m, p, q, f, x \} </math>

{| class="wikitable"
|- |-
! Rule !! Condition !! Expression ! Condition !! Expression
|-()
| <math> \operatorname{false} </math>|| <math> \operatorname{drop-formal} </math>
|- |-
| <math> \operatorname{true} \land \{p\} \subset F </math> || <math> \lambda x.\operatorname{drop-formal} </math>
| 2
| <math> \neg (\operatorname{false}) </math>
| <math> \operatorname{drop-formal} </math>
|- |-
| <math> \neg (\operatorname{true} \land \{n\} \subset F </math>) || <math> \lambda x.\operatorname{drop-formal}, F] </math>
| 1
| <math> \operatorname{true} \and \{p\} \subset \{ k, m, p, q, f, x \} </math>
| <math> \lambda x.\operatorname{drop-formal} </math>
|- |-
| || <math> \lambda x.\lambda y.\operatorname{drop-formal} </math>
| 2
| <math> \neg (\operatorname{true} \and \{n\} \subset \{ k, m, p, q, f, x \} </math>)
| <math> \lambda x.\operatorname{drop-formal}, V] </math>
|- |-
| || <math> \lambda x.\lambda y.p\ x\ y </math>
| 3
|
| <math> \lambda x.\lambda y.\operatorname{drop-formal} </math>
|-
| || || <math> \lambda x.\lambda y.p\ x\ y </math>
|} |}


Line 566: Line 1,362:


Starting with the function definition of the Y-combinator, Starting with the function definition of the Y-combinator,
:<math>\operatorname{let} p\ f\ x = f\ (x\ x) \and q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p\ </math> :<math>\operatorname{let} p\ f\ x = f\ (x\ x) \land q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p\ </math>


{| class="wikitable" {| class="wikitable"
Line 573: Line 1,369:
|- |-
| |
| <math> \operatorname{let} p\ f\ x = f\ (x\ x) \and q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p </math> | <math> \operatorname{let} p\ f\ x = f\ (x\ x) \land q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p </math>
|- |-
| ''lambda-preprocess'' | ''abstract'' * 4
| <math> \operatorname{let} p\ f\ x = f\ (x\ x) \operatorname{in} \operatorname{let} q\ p\ f = (p\ f)\ (p\ f) \operatorname{in} q\ p </math> | <math>\operatorname{let} p = \lambda f.\lambda x.f\ (x\ x) \land q = \lambda p.\lambda f.(p\ f)\ (p\ f) \operatorname{in} q\ p </math>
|- |-
| ''lambda-process'' | ''lambda-abstract-tran''
| <math>\operatorname{let} p = \lambda f.\lambda x.f\ (x\ x) \operatorname{in} \operatorname{let} q = \lambda p.\lambda f.(p\ f)\ (p\ f) \operatorname{in} q\ p </math>
|-
| ''lambda-convert''
| <math> (\lambda q.(\lambda p. q\ p)\ (\lambda f.\lambda x.f\ (x\ x)))\ (\lambda p.\lambda f.(p\ f)\ (p\ f)) </math> | <math> (\lambda q.(\lambda p. q\ p)\ (\lambda f.\lambda x.f\ (x\ x)))\ (\lambda p.\lambda f.(p\ f)\ (p\ f)) </math>
|- |-
Line 601: Line 1,394:


== See also == == See also ==

* ]
* ]
* ]
* ]
* ] * ]
* ]


== References == == References ==
Line 607: Line 1,406:


==External links== ==External links==
*
*
*{{cite web |first=Ken |last=Slonneger |first2=Barry |last2=Kurtz |url=http://homepage.cs.uiowa.edu/~slonnegr/plf/Lecture05.pdf |title=5. Some discussion of let expressions |work=Programming Language Foundations |publisher=University of Iowa }}
*


] ]
] ]
]

Latest revision as of 02:56, 2 October 2024

Globalization meta-process

Lambda lifting is a meta-process that restructures a computer program so that functions are defined independently of each other in a global scope. An individual "lift" transforms a local function into a global function. It is a two step process, consisting of;

  • Eliminating free variables in the function by adding parameters.
  • Moving functions from a restricted scope to broader or global scope.

The term "lambda lifting" was first introduced by Thomas Johnsson around 1982 and was historically considered as a mechanism for implementing functional programming languages. It is used in conjunction with other techniques in some modern compilers.

Lambda lifting is not the same as closure conversion. It 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 technique may be used on individual functions, in code refactoring, to make a function usable outside the scope in which it was written. Lambda lifts may also be repeated, in order to transform the program. Repeated lifts may be used to convert a program written in lambda calculus into a set of recursive functions, without lambdas. This demonstrates the equivalence of programs written in lambda calculus and programs written as functions. However it does not demonstrate the soundness of lambda calculus for deduction, 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 (see Curry's paradox).

Lambda lifting is expensive on processing time for the compiler. An efficient implementation of lambda lifting is O ( n 2 ) {\displaystyle O(n^{2})} on processing time for the compiler.

In the untyped lambda calculus, where the basic types are functions, lifting may change the result of beta reduction of a lambda expression. The resulting functions will have the same meaning, in a mathematical sense, but are not regarded as the same function in the untyped lambda calculus. See also intensional versus extensional equality.

The reverse operation to lambda lifting is lambda dropping.

Lambda dropping 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 it 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.

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:

  1. Rename the functions so that each function has a unique name.
  2. Replace each free variable with an additional argument to the enclosing function, and pass that argument to every use of the function.
  3. Replace every local function definition that has no free variables with an identical global function.
  4. 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 a parameter:

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));
}

Lambda lifting versus closures

Lambda lifting and closure are both methods for implementing block structured programs. It implements block structure by eliminating it. All functions are lifted to the global level. Closure conversion provides a "closure" which links the current frame to other frames. Closure conversion takes less compile time.

Recursive functions, and block structured programs, with or without lifting, may be implemented using a stack based implementation, which is simple and efficient. However a stack frame based implementation must be strict (eager). The stack frame based implementation requires that the life of functions be last-in, first-out (LIFO). That is, the most recent function to start its calculation must be the first to end.

Some functional languages (such as Haskell) are implemented using lazy evaluation, which delays calculation until the value is needed. The lazy implementation strategy gives flexibility to the programmer. Lazy evaluation requires delaying the call to a function until a request is made to the value calculated by the function. One implementation is to record a reference to a "frame" of data describing the calculation, in place of the value. Later when the value is required, the frame is used to calculate the value, just in time for when it is needed. The calculated value then replaces the reference.

The "frame" is similar to a stack frame, the difference being that it is not stored on the stack. Lazy evaluation requires that all the data required for the calculation be saved in the frame. If the function is "lifted", then the frame needs only record the function pointer, and the parameters to the function. Some modern languages use garbage collection in place of stack based allocation to manage the life of variables. In a managed, garbage collected environment, a closure records references to the frames from which values may be obtained. In contrast a lifted function has parameters for each value needed in the calculation.

Let expressions and lambda calculus

The Let expression is useful in describing lifting and dropping, and in describing the relationship between recursive equations and lambda expressions. Most functional languages have let expressions. Also, block structured programming languages like ALGOL and Pascal are similar in that they too allow the local definition of a function for use in a restricted scope.

The let expression used here is a fully mutually recursive version of let rec, as implemented in many functional languages.

Let expressions are related to Lambda calculus. Lambda calculus has a simple syntax and semantics, and is good for describing Lambda lifting. It is convenient to describe lambda lifting as a translations from lambda to a let expression, and lambda dropping as the reverse. This is because let expressions allow mutual recursion, which is, in a sense, more lifted than is supported in lambda calculus. Lambda calculus does not support mutual recursion and only one function may be defined at the outermost global scope.

Conversion rules which describe translation without lifting are given in the Let expression article.

The following rules describe the equivalence of lambda and let expressions,

Name Law
Eta-reduction equivalence f   x = y f = λ x . y {\displaystyle f\ x=y\equiv f=\lambda x.y}
Let-Lambda equivalence f F V ( E ) ( let f : f = E in L ( λ f . L )   E )   (where  f  is a variable name.) {\displaystyle f\notin FV(E)\to (\operatorname {let} f:f=E\operatorname {in} L\equiv (\lambda f.L)\ E)\ {\text{(where }}f{\text{ is a variable name.)}}}
Let combination x F V ( E ) ( let v , , w , x : E F in L let v , , w : E in let x : F in L ) {\displaystyle x\notin FV(E)\to (\operatorname {let} v,\dots ,w,x:E\land F\operatorname {in} L\equiv \operatorname {let} v,\dots ,w:E\operatorname {in} \operatorname {let} x:F\operatorname {in} L)}

Meta-functions will be given that describe lambda lifting and dropping. 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.
  • {\displaystyle \equiv } will be used for equals in the meta program.
  • _ {\displaystyle \_} represents a dummy variable, or an unknown value.

For simplicity the first rule given that matches will be applied. The rules also assume that the lambda expressions have been pre-processed so that each lambda abstraction has a unique name.

The substitution operator is used extensively. The expression L [ G := S ] {\displaystyle L} means substitute every occurrence of G in L by S and return the expression. The definition used is extended to cover the substitution of expressions, from the definition given on the Lambda calculus page. The matching of expressions should compare expressions for alpha equivalence (renaming of variables).

Lambda lifting in lambda calculus

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.

Lambda lifts may be used on individual functions, in code refactoring, to make a function usable outside the scope in which it was written. Such lifts may also be repeated, until the expression has no lambda abstractions, in order to transform the program.

Lambda lift

A lift is given a sub-expression within an expression to lift to the top of that expression. The expression may be part of a larger program. This allows control of where the sub-expression is lifted to. The lambda lift operation used to perform a lift within a program is,

l a m b d a - l i f t - o p [ S , L , P ] = P [ L := l a m b d a - l i f t [ S , L ] ] {\displaystyle \operatorname {lambda-lift-op} =P]}

The sub expression may be either a lambda abstraction, or a lambda abstraction applied to a parameter.

Two types of lift are possible.

An anonymous lift has a lift expression which is a lambda abstraction only. It is regarded as defining an anonymous function. A name must be created for the function.

A named lift expression has a lambda abstraction applied to an expression. This lift is regarded as a named definition of a function.

Anonymous lift

An anonymous lift takes a lambda abstraction (called S). For S;

  • Create a name for the function that will replace S (called V). Make sure that the name identified by V has not been used.
  • Add parameters to V, for all the free variables in S, to create an expression G (see make-call).

The lambda lift is the substitution of the lambda abstraction S for a function application, along with the addition of a definition for the function.

l a m b d a - l i f t [ S , L ] let V : d e - l a m b d a [ G = S ] in L [ S := G ] {\displaystyle \operatorname {lambda-lift} \equiv \operatorname {let} V:\operatorname {de-lambda} \operatorname {in} L}

The new lambda expression has S substituted for G. Note that L 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,

G = m a k e - c a l l [ V , FV [ S ] ] {\displaystyle G=\operatorname {make-call} ]}

where V is the function name. It must be a new variable, i.e. a name not already used in the lambda expression,

V vars [ let F in L ] {\displaystyle V\not \in \operatorname {vars} }

where vars [ E ] {\displaystyle \operatorname {vars} } is a meta function that returns the set of variables used in E.

Example for anonymous lift.
For example,
F = true L = λ f . ( λ x . f   ( x   x ) )   ( λ x . f   ( x   x ) ) S = λ x . f   ( x   x ) G = p   f {\displaystyle {\begin{aligned}F&=\operatorname {true} \\L&=\lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x))\\S&=\lambda x.f\ (x\ x)\\G&=p\ f\end{aligned}}}
d e - l a m b d a [ p   f = λ x . f   ( x   x ) ] p   f   x = f   ( x   x ) {\displaystyle \operatorname {de-lambda} \equiv p\ f\ x=f\ (x\ x)}

See de-lambda in Conversion from lambda to let expressions. The result is,

l a m b d a - l i f t [ λ x . f   ( x   x ) , let true in λ f . ( λ x . f   ( x   x ) )   ( λ x . f   ( x   x ) ) ] let p   f   x = f   ( x   x ) in λ f . ( p   f )   ( p   f ) {\displaystyle \operatorname {lambda-lift} \equiv \operatorname {let} p\ f\ x=f\ (x\ x)\operatorname {in} \lambda f.(p\ f)\ (p\ f)}
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,

  • X V m a k e - c a l l [ H , V ] m a k e - c a l l [ H , V ¬ { X } ]   X {\displaystyle X\in V\to \operatorname {make-call} \equiv \operatorname {make-call} \ X}
  • m a k e - c a l l [ H , { } ] H {\displaystyle \operatorname {make-call} \equiv H}
Example of call construction.
S = λ x . f   ( x   x ) {\displaystyle S=\lambda x.f\ (x\ x)}
FV ( S ) = { f } {\displaystyle \operatorname {FV} (S)=\{f\}}
G m a k e - c a l l [ p , FV [ S ] ] m a k e - c a l l [ p , { f } ] m a k e - c a l l [ p , { } ]   f p   f {\displaystyle G\equiv \operatorname {make-call} ]\equiv \operatorname {make-call} \equiv \operatorname {make-call} \ f\equiv p\ f}

Named lift

The named lift is similar to the anonymous lift except that the function name V is provided.

l a m b d a - l i f t [ ( λ V . E )   S , L ] let V : d e - l a m b d a [ G = S ] in L [ ( λ V . E )   S := E [ V := G ] ] {\displaystyle \operatorname {lambda-lift} \equiv \operatorname {let} V:\operatorname {de-lambda} \operatorname {in} L]}

As for the anonymous lift, the expression G is constructed from V by applying the free variables of S. It is defined by,

G = m a k e - c a l l [ V , FV [ S ] ] {\displaystyle G=\operatorname {make-call} ]}
Example for named lift.

For example,

V = x E = f   ( x   x ) S = ( λ x . f   ( x   x ) ) L = λ f . ( λ x . f   ( x   x ) )   ( λ x . f   ( x   x ) ) G = x   f {\displaystyle {\begin{aligned}V&=x\\E&=f\ (x\ x)\\S&=(\lambda x.f\ (x\ x))\\L&=\lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x))\\G&=x\ f\end{aligned}}}
E [ V := G ] = f   ( x   x ) [ x := x   f ] = f   ( ( x   f )   ( x   f ) ) {\displaystyle E=f\ (x\ x)=f\ ((x\ f)\ (x\ f))}
L [ ( λ V . E )   F := E [ V := G ] ] = L [ ( λ x . f   ( x   x ) )   ( λ x . f   ( x   x ) ) := f   ( ( x   f )   ( x   f ) ) ] = λ f . f   ( ( x   f )   ( x   f ) ) {\displaystyle L]=L=\lambda f.f\ ((x\ f)\ (x\ f))}
d e - l a m b d a [ x   f = λ y . f   ( y   y ) ] x   f   y = f   ( y   y ) {\displaystyle \operatorname {de-lambda} \equiv x\ f\ y=f\ (y\ y)}

See de-lambda in Conversion from lambda to let expressions. The result is,

gives,

l a m b d a - l i f t [ ( λ x . f   ( x   x ) )   ( λ x . f   ( x   x ) ) , λ f . ( λ x . f   ( x   x ) )   ( λ x . f   ( x   x ) ) ] let x   f   y = f   ( y   y ) in λ f . ( x   f )   ( x   f ) {\displaystyle \operatorname {lambda-lift} \equiv \operatorname {let} x\ f\ y=f\ (y\ y)\operatorname {in} \lambda f.(x\ f)\ (x\ f)}

Lambda-lift transformation

A lambda lift transformation takes a lambda expression and lifts all lambda abstractions to the top of the expression. The abstractions are then translated into recursive functions, which eliminates the lambda abstractions. The result is a functional program in the form,

  • let M in N {\displaystyle \operatorname {let} M\operatorname {in} N}

where M is a series of function definitions, and N is the expression representing the value returned.

For example,

l a m b d a - l i f t - t r a n [ λ f . ( λ x . f   ( x   x ) )   ( λ x . f   ( x   x ) ) ] let p   f   x = f   ( x   x ) q   p   f = ( p   f )   ( p   f ) in q   p {\displaystyle \operatorname {lambda-lift-tran} \equiv \operatorname {let} p\ f\ x=f\ (x\ x)\land q\ p\ f=(p\ f)\ (p\ f)\operatorname {in} q\ p}

The de-let meta function may then be used to convert the result back into lambda calculus.

d e - l e t [ l a m b d a - l i f t - t r a n [ λ f . ( λ x . f   ( x   x ) )   ( λ x . f   ( x   x ) ) ] ] ( λ p . ( λ q . q   p )   λ p . λ f . ( p   f )   ( p   f ) )   λ f . λ x . f   ( x   x ) {\displaystyle \operatorname {de-let} ]\equiv (\lambda p.(\lambda q.q\ p)\ \lambda p.\lambda f.(p\ f)\ (p\ f))\ \lambda f.\lambda x.f\ (x\ x)}

The processing of transforming the lambda expression is a series of lifts. Each lift has,

  • A sub expression chosen for it by the function lift-choice. 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,
{ l a m b d a - l i f t - t r a n [ L ] = d r o p - p a r a m s - t r a n [ m e r g e - l e t [ l a m b d a - a p p l y [ L ] ] ] l a m b d a - a p p l y [ L ] = l a m b d a - p r o c e s s [ l i f t - c h o i c e [ L ] , L ] l a m b d a - p r o c e s s [ none , L ] = L l a m b d a - p r o c e s s [ S , L ] = l a m b d a - a p p l y [ l a m b d a - l i f t [ S , L ] ] {\displaystyle {\begin{cases}\operatorname {lambda-lift-tran} =\operatorname {drop-params-tran} ]]\\\operatorname {lambda-apply} =\operatorname {lambda-process} ,L]\\\operatorname {lambda-process} =L\\\operatorname {lambda-process} =\operatorname {lambda-apply} ]\end{cases}}}

After the lifts are applied the lets are combined together into a single let.

{ m e r g e - l e t [ let V : E in let W : F in G ] = m e r g e - l e t [ let V , W : E F in G ] m e r g e - l e t [ E ] = E {\displaystyle {\begin{cases}\operatorname {merge-let} =\operatorname {merge-let} \\\operatorname {merge-let} =E\end{cases}}}

Then Parameter dropping is applied to remove parameters that are not necessary in the "let" expression. The let expression allows the function definitions to refer to each other directly, whereas lambda abstractions are strictly hierarchical, and a function may not directly refer to itself.

Choosing the expression for lifting

There are two different ways that an expression may be selected for lifting. The first treats all lambda abstractions as defining anonymous functions. The second, treats lambda abstractions which are applied to a parameter as defining a function. Lambda abstractions applied to a parameter have a dual interpretation as either a let expression defining a function, or as defining an anonymous function. Both interpretations are valid.

These two predicates are needed for both definitions.

lambda-free - An expression containing no lambda abstractions.

{ l a m b d a - f r e e [ λ F . X ] = false l a m b d a - f r e e [ V ] = true l a m b d a - f r e e [ M   N ] = l a m b d a - f r e e [ M ] l a m b d a - f r e e [ N ] {\displaystyle {\begin{cases}\operatorname {lambda-free} =\operatorname {false} \\\operatorname {lambda-free} =\operatorname {true} \\\operatorname {lambda-free} =\operatorname {lambda-free} \land \operatorname {lambda-free} \end{cases}}}

lambda-anon - An anonymous function. An expression like λ x 1 .   . . .   λ x n . X {\displaystyle \lambda x_{1}.\ ...\ \lambda x_{n}.X} where X is lambda free.

{ l a m b d a - a n o n [ λ F . X ] = l a m b d a - f r e e [ X ] l a m b d a - a n o n [ X ] l a m b d a - a n o n [ V ] = false l a m b d a - a n o n [ M   N ] = false {\displaystyle {\begin{cases}\operatorname {lambda-anon} =\operatorname {lambda-free} \lor \operatorname {lambda-anon} \\\operatorname {lambda-anon} =\operatorname {false} \\\operatorname {lambda-anon} =\operatorname {false} \end{cases}}}
Choosing anonymous functions only for lifting

Search for the deepest anonymous abstraction, so that when the lift is applied the function lifted will become a simple equation. This definition does not recognize a lambda abstractions with a parameter as defining a function. All lambda abstractions are regarded as defining anonymous functions.

lift-choice - The first anonymous found in traversing the expression or none if there is no function.

  1. l a m b d a - a n o n [ X ] l i f t - c h o i c e [ X ] = X {\displaystyle \operatorname {lambda-anon} \to \operatorname {lift-choice} =X}
  2. l i f t - c h o i c e [ λ F . X ] = l i f t - c h o i c e [ X ] {\displaystyle \operatorname {lift-choice} =\operatorname {lift-choice} }
  3. l i f t - c h o i c e [ M ] none l i f t - c h o i c e [ M   N ] = l i f t - c h o i c e [ M ] {\displaystyle \operatorname {lift-choice} \neq \operatorname {none} \to \operatorname {lift-choice} =\operatorname {lift-choice} }
  4. l i f t - c h o i c e [ M   N ] = l i f t - c h o i c e [ N ] {\displaystyle \operatorname {lift-choice} =\operatorname {lift-choice} }
  5. l i f t - c h o i c e [ V ] = none {\displaystyle \operatorname {lift-choice} =\operatorname {none} }

For example,

Lambda choice on λ f . ( λ x . f   ( x   x ) )   ( λ y . f   ( y   y ) ) {\displaystyle \lambda f.(\lambda x.f\ (x\ x))\ (\lambda y.f\ (y\ y))} is λ x . f   ( x   x ) {\displaystyle \lambda x.f\ (x\ x)}
Rule function type choice
2 l i f t - c h o i c e [ λ f . ( λ x . f   ( x   x ) )   ( λ y . f   ( y   y ) ) ] {\displaystyle \operatorname {lift-choice} }
3 l i f t - c h o i c e [ ( λ x . f   ( x   x ) )   ( λ y . f   ( y   y ) ) ] {\displaystyle \operatorname {lift-choice} }
1 anon l i f t - c h o i c e [ λ x . f   ( x   x ) ] {\displaystyle \operatorname {lift-choice} }
λ x . f   ( x   x ) {\displaystyle \lambda x.f\ (x\ x)}
Lambda choice on λ f . ( p   f )   ( p   f ) {\displaystyle \lambda f.(p\ f)\ (p\ f)} is λ f . ( p   f )   ( p   f ) {\displaystyle \lambda f.(p\ f)\ (p\ f)}
Rule function type choice
2 anon l i f t - c h o i c e [ λ f . ( p   f )   ( p   f ) ] {\displaystyle \operatorname {lift-choice} }
2 λ f . ( p   f )   ( p   f ) {\displaystyle \lambda f.(p\ f)\ (p\ f)}
Choosing named and anonymous functions for lifting

Search for the deepest named or anonymous function definition, so that when the lift is applied the function lifted will become a simple equation. This definition recognizes a lambda abstraction with an actual parameter as defining a function. Only lambda abstractions without an application are treated as anonymous functions.

lambda-named
A named function. An expression like ( λ F . M )   N {\displaystyle (\lambda F.M)\ N} where M is lambda free and N is lambda free or an anonymous function.
l a m b d a - n a m e d [ ( λ F . M )   N ] = l a m b d a - f r e e [ M ] l a m b d a - a n o n [ N ] l a m b d a - n a m e d [ λ F . X ] = false l a m b d a - n a m e d [ V ] = false {\displaystyle {\begin{array}{l}\operatorname {lambda-named} =\operatorname {lambda-free} \land \operatorname {lambda-anon} \\\operatorname {lambda-named} =\operatorname {false} \\\operatorname {lambda-named} =\operatorname {false} \end{array}}}
lift-choice
The first anonymous or named function found in traversing the expression or none if there is no function.
  1. l a m b d a - n a m e d [ X ] l a m b d a - a n o n [ X ] l i f t - c h o i c e [ X ] = X {\displaystyle \operatorname {lambda-named} \lor \operatorname {lambda-anon} \to \operatorname {lift-choice} =X}
  2. l i f t - c h o i c e [ λ F . X ] = l i f t - c h o i c e [ X ] {\displaystyle \operatorname {lift-choice} =\operatorname {lift-choice} }
  3. l i f t - c h o i c e [ M ] none l i f t - c h o i c e [ M   N ] = l i f t - c h o i c e [ M ] {\displaystyle \operatorname {lift-choice} \neq \operatorname {none} \to \operatorname {lift-choice} =\operatorname {lift-choice} }
  4. l i f t - c h o i c e [ M   N ] = l i f t - c h o i c e [ N ] {\displaystyle \operatorname {lift-choice} =\operatorname {lift-choice} }
  5. l i f t - c h o i c e [ V ] = none {\displaystyle \operatorname {lift-choice} =\operatorname {none} }

For example,

Lambda choice on λ f . ( λ x . f   ( x   x ) )   ( λ y . f   ( y   y ) ) {\displaystyle \lambda f.(\lambda x.f\ (x\ x))\ (\lambda y.f\ (y\ y))} is ( λ x . f   ( x   x ) )   ( λ y . f   ( y   y ) ) {\displaystyle (\lambda x.f\ (x\ x))\ (\lambda y.f\ (y\ y))}
Rule function type choice
2 l i f t - c h o i c e [ λ f . ( λ x . f   ( x   x ) )   ( λ y . f   ( y   y ) ) ] {\displaystyle \operatorname {lift-choice} }
1 named l i f t - c h o i c e [ ( λ x . f   ( x   x ) )   ( λ y . f   ( y   y ) ) ] {\displaystyle \operatorname {lift-choice} }
( λ x . f   ( x   x ) )   ( λ y . f   ( y   y ) ) {\displaystyle (\lambda x.f\ (x\ x))\ (\lambda y.f\ (y\ y))}
Lambda choice on λ f . f   ( ( x   f )   ( x   f ) ) {\displaystyle \lambda f.f\ ((x\ f)\ (x\ f))} is λ f . f   ( ( x   f )   ( x   f ) ) {\displaystyle \lambda f.f\ ((x\ f)\ (x\ f))}
Rule function type choice
1 anon l i f t - c h o i c e [ λ f . f   ( ( x   f )   ( x   f ) ) ] {\displaystyle \operatorname {lift-choice} }
λ f . f   ( ( x   f )   ( x   f ) ) {\displaystyle \lambda f.f\ ((x\ f)\ (x\ f))}

Examples

For example, the Y combinator,

λ f . ( λ x . f   ( x   x ) )   ( λ x . f   ( x   x ) ) {\displaystyle \lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x))}

is lifted as,

let x   f   y = f   ( y   y ) q   x   f = f   ( ( x   f )   ( x   f ) ) in q   x {\displaystyle \operatorname {let} x\ f\ y=f\ (y\ y)\land q\ x\ f=f\ ((x\ f)\ (x\ f))\operatorname {in} q\ x}

and after Parameter dropping,

let x   f   y = f   ( y   y ) q   f = f   ( ( x   f )   ( x   f ) ) in q {\displaystyle \operatorname {let} x\ f\ y=f\ (y\ y)\land q\ f=f\ ((x\ f)\ (x\ f))\operatorname {in} q}

As a lambda expression (see Conversion from let to lambda expressions),

( λ x . ( λ q . q )   λ f . f   ( x   f )   ( x   f ) )   λ f . λ y . f   ( y   y ) {\displaystyle (\lambda x.(\lambda q.q)\ \lambda f.f\ (x\ f)\ (x\ f))\ \lambda f.\lambda y.f\ (y\ y)}
Lifting named and anonymous functions
Lambda Expression Function From To Variables
1 λ f . ( λ x . f   ( x   x ) )   ( λ x . f   ( x   x ) ) {\displaystyle \lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x))} true ( λ x . f   ( x   x ) )   ( λ x . f   ( x   x ) ) {\displaystyle (\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x))} x   f {\displaystyle x\ f} { x , f } {\displaystyle \{x,f\}}
2

( λ f . ( λ x . f   ( x   x ) ) ( λ x . f   ( x   x ) ) ) {\displaystyle (\lambda f.(\lambda x.f\ (x\ x))(\lambda x.f\ (x\ x)))}

[ ( λ x . f   ( x   x ) )   ( λ x . f   ( x   x ) ) := f   ( ( x   f )   ( x   f ) ) ] {\displaystyle }
x   f = λ y . f   ( y   y ) {\displaystyle x\ f=\lambda y.f\ (y\ y)} { x , f , p } {\displaystyle \{x,f,p\}}
3 λ f . f   ( ( x   f )   ( x   f ) ) {\displaystyle \lambda f.f\ ((x\ f)\ (x\ f))} x   f   y = f   ( y   y ) {\displaystyle x\ f\ y=f\ (y\ y)} λ f . f   ( ( x   f )   ( x   f ) ) {\displaystyle \lambda f.f\ ((x\ f)\ (x\ f))} q   x {\displaystyle q\ x} { x , f , p } {\displaystyle \{x,f,p\}}
4 λ f . f   ( ( x   f )   ( x   f ) ) [ λ f . f   ( ( x   f )   ( x   f ) ) := q   x ] {\displaystyle \lambda f.f\ ((x\ f)\ (x\ f))} x   f   y = f   ( y   y ) q   x = λ f . f   ( ( x   f )   ( x   f ) ) {\displaystyle x\ f\ y=f\ (y\ y)\land q\ x=\lambda f.f\ ((x\ f)\ (x\ f))} { x , f , p , q } {\displaystyle \{x,f,p,q\}}
5 q   x {\displaystyle q\ x} x   f   y = f   ( y   y ) q   x   f = f   ( ( x   f )   ( x   f ) ) {\displaystyle x\ f\ y=f\ (y\ y)\land q\ x\ f=f\ ((x\ f)\ (x\ f))} { x , f , p , q } {\displaystyle \{x,f,p,q\}}

If lifting anonymous functions only, the Y combinator is,

let p   f   x = f   ( x   x ) q   p   f = ( p   f )   ( p   f ) in q   p {\displaystyle \operatorname {let} p\ f\ x=f\ (x\ x)\land q\ p\ f=(p\ f)\ (p\ f)\operatorname {in} q\ p}

and after Parameter dropping,

let p   f   x = f   ( x   x ) q   f = ( p   f )   ( p   f ) in q {\displaystyle \operatorname {let} p\ f\ x=f\ (x\ x)\land q\ f=(p\ f)\ (p\ f)\operatorname {in} q}

As a lambda expression,

( λ p . ( λ q . q )   λ f . ( p   f )   ( p   f ) )   λ f . λ x . f   ( x   x ) {\displaystyle (\lambda p.(\lambda q.q)\ \lambda f.(p\ f)\ (p\ f))\ \lambda f.\lambda x.f\ (x\ x)}
Lifting anonymous functions only
Lambda Expression Function From To Variables
1 λ f . ( λ x . f   ( x   x ) )   ( λ x . f   ( x   x ) ) {\displaystyle \lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x))} true λ x . f   ( x   x ) {\displaystyle \lambda x.f\ (x\ x)} p   f {\displaystyle p\ f} { x , f } {\displaystyle \{x,f\}}
2 ( λ f . ( λ x . f   ( x   x ) ) ( λ x . f   ( x   x ) ) ) [ λ x . f   ( x   x ) := p   f ] {\displaystyle (\lambda f.(\lambda x.f\ (x\ x))(\lambda x.f\ (x\ x)))} p   f = λ x . f   ( x   x ) {\displaystyle p\ f=\lambda x.f\ (x\ x)} { x , f , p } {\displaystyle \{x,f,p\}}
3 λ f . ( p   f )   ( p   f ) {\displaystyle \lambda f.(p\ f)\ (p\ f)} p   f   x = f   ( x   x ) {\displaystyle p\ f\ x=f\ (x\ x)} λ f . ( p   f )   ( p   f ) {\displaystyle \lambda f.(p\ f)\ (p\ f)} q   p {\displaystyle q\ p} { x , f , p } {\displaystyle \{x,f,p\}}
4 λ f . ( p   f )   ( p   f ) [ λ f . ( p   f )   ( p   f ) := q   p ] {\displaystyle \lambda f.(p\ f)\ (p\ f)} p   f   x = f   ( x   x ) q   p = λ f . ( p   f )   ( p   f ) {\displaystyle p\ f\ x=f\ (x\ x)\land q\ p=\lambda f.(p\ f)\ (p\ f)} { x , f , p , q } {\displaystyle \{x,f,p,q\}}
5 q   p {\displaystyle q\ p} p   f   x = f   ( x   x ) q   p   f = ( p   f )   ( p   f ) {\displaystyle p\ f\ x=f\ (x\ x)\land q\ p\ f=(p\ f)\ (p\ f)} { x , f , p , q } {\displaystyle \{x,f,p,q\}}

The first sub expression to be chosen for lifting is λ x . f   ( x   x ) {\displaystyle \lambda x.f\ (x\ x)} . This transforms the lambda expression into λ f . ( p   f )   ( p   f ) {\displaystyle \lambda f.(p\ f)\ (p\ f)} and creates the equation p   f   x = f ( x   x ) {\displaystyle p\ f\ x=f(x\ x)} .

The second sub expression to be chosen for lifting is λ f . ( p   f )   ( p   f ) {\displaystyle \lambda f.(p\ f)\ (p\ f)} . This transforms the lambda expression into q   p {\displaystyle q\ p} and creates the equation q   p   f = ( p   f )   ( p   f ) {\displaystyle q\ p\ f=(p\ f)\ (p\ f)} .

And the result is,

let p   f   x = f   ( x   x ) q   p   f = ( p   f )   ( p   f ) in q   p   {\displaystyle \operatorname {let} p\ f\ x=f\ (x\ x)\land q\ p\ f=(p\ f)\ (p\ f)\operatorname {in} q\ p\ }

Surprisingly this result is simpler than the one obtained from lifting named functions.

Execution

Apply function to K,

{ λ f . ( λ x . f   ( x   x ) )   ( λ x . f   ( x   x ) )   K   let   p   f   x = f   ( x   x ) q   p   f = ( p   f )   ( p   f )   in   q   p   K ( λ x . K   ( x   x ) )   ( λ x . K   ( x   x ) )   let   p   f   x = f   ( x   x ) q   p   f = ( p   f )   ( p   f )   in   p   K   ( p   K ) K   ( ( λ x . K   ( x   x ) )   ( λ x . K   ( x   x ) ) )   let   p   f   x = f   ( x   x ) q   p   f = p   f   ( p   f )   in   K   ( p   K   ( p   K ) ) {\displaystyle {\begin{cases}\lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x))\ K&\ \operatorname {let} \ p\ f\ x=f\ (x\ x)\land q\ p\ f=(p\ f)\ (p\ f)\ \operatorname {in} \ q\ p\ K\\(\lambda x.K\ (x\ x))\ (\lambda x.K\ (x\ x))&\ \operatorname {let} \ p\ f\ x=f\ (x\ x)\land q\ p\ f=(p\ f)\ (p\ f)\ \operatorname {in} \ p\ K\ (p\ K)\\K\ ((\lambda x.K\ (x\ x))\ (\lambda x.K\ (x\ x)))&\ \operatorname {let} \ p\ f\ x=f\ (x\ x)\land q\ p\ f=p\ f\ (p\ f)\ \operatorname {in} \ K\ (p\ K\ (p\ K))\\\end{cases}}}

So,

( λ x . K   ( x   x ) )   ( λ x . K   ( x   x ) ) = K   ( ( λ x . K   ( x   x ) )   ( λ x . K   ( x   x ) ) ) )   {\displaystyle (\lambda x.K\ (x\ x))\ (\lambda x.K\ (x\ x))=K\ ((\lambda x.K\ (x\ x))\ (\lambda x.K\ (x\ x))))\ }

or

p   K   ( p   K ) = K   ( p   K   ( p   K ) ) {\displaystyle p\ K\ (p\ K)=K\ (p\ K\ (p\ K))}

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 is making the scope of functions smaller and using the context from the reduced scope to reduce the number of parameters to functions. Reducing the number of parameters makes functions easier to comprehend.

In the Lambda lifting section, a meta function for first lifting and then converting the resulting lambda expression into recursive equation was described. The Lambda 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.

Lambda dropping is performed in two steps,

Lambda drop

A Lambda drop is applied to an expression which is part of a program. Dropping is controlled by a set of expressions from which the drop will be excluded.

l a m b d a - d r o p - o p [ L , P , X ] = P [ L := d r o p - p a r a m s - t r a n [ s i n k - t e s t [ L , X ] ] ] {\displaystyle \operatorname {lambda-drop-op} =P]]}

where,

L is the lambda abstraction to be dropped.
P is the program
X is a set of expressions to be excluded from dropping.

Lambda drop transformation

The lambda drop transformation sinks all abstractions in an expression. Sinking is excluded from expressions in a set of expressions,

l a m b d a - d r o p - t r a n [ L , X ] = d r o p - p a r a m s - t r a n [ s i n k - t r a n [ d e - l e t [ L , X ] ] ] {\displaystyle \operatorname {lambda-drop-tran} =\operatorname {drop-params-tran} ]]}

where,

L is the expression to be transformed.
X is a set of sub expressions to be excluded from the dropping.

sink-tran sinks each abstraction, starting from the innermost,

{ s i n k - t r a n [ ( λ N . B )   Y , X ] = s i n k - t e s t [ ( λ N . s i n k - t r a n [ B ] )   s i n k - t r a n [ Y ] , X ] s i n k - t r a n [ λ N . B , X ] = λ N . s i n k - t r a n [ B , X ] s i n k - t r a n [ M   N , X ] = s i n k - t r a n [ M , X ]   s i n k - t r a n [ M , X ] s i n k - t r a n [ V , X ] = V {\displaystyle {\begin{cases}\operatorname {sink-tran} =\operatorname {sink-test} )\ \operatorname {sink-tran} ,X]\\\operatorname {sink-tran} =\lambda N.\operatorname {sink-tran} \\\operatorname {sink-tran} =\operatorname {sink-tran} \ \operatorname {sink-tran} \\\operatorname {sink-tran} =V\end{cases}}}

Abstraction sinking

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.

{ E FV [ G ] E FV [ H ] sink [ ( λ E . G   H )   Y , X ] = G   H E FV [ G ] E FV [ H ] sink [ ( λ E . G   H )   Y , X ] = s i n k - t e s t [ G   s i n k - t e s t [ ( λ E . H )   Y , X ] ] E FV [ G ] E FV [ H ] sink [ ( λ E . G   H )   Y , X ] = ( s i n k - t e s t [ ( λ E . G )   Y , X ] )   H E FV [ G ] E FV [ H ] sink [ ( λ E . G   H )   Y , X ] = ( λ E . G   H )   Y {\displaystyle {\begin{cases}E\not \in \operatorname {FV} \land E\not \in \operatorname {FV} \to \operatorname {sink} =G\ H\\E\not \in \operatorname {FV} \land E\in \operatorname {FV} \to \operatorname {sink} =\operatorname {sink-test} ]\\E\in \operatorname {FV} \land E\not \in \operatorname {FV} \to \operatorname {sink} =(\operatorname {sink-test} )\ H\\E\in \operatorname {FV} \land E\in \operatorname {FV} \to \operatorname {sink} =(\lambda E.G\ H)\ Y\end{cases}}}

Abstraction. Use renaming to insure that the variable names are all distinct.

V W sink [ ( λ V . λ W . E )   Y , X ] = λ W . s i n k - t e s t [ ( λ V . E )   Y , X ] {\displaystyle V\neq W\to \operatorname {sink} =\lambda W.\operatorname {sink-test} }

Variable - 2 cases.

E V sink [ ( λ E . V )   Y , X ] = V {\displaystyle E\neq V\to \operatorname {sink} =V}
E = V sink [ ( λ E . V )   Y , X ] = Y {\displaystyle E=V\to \operatorname {sink} =Y}

Sink test excludes expressions from dropping,

L X s i n k - t e s t [ L , X ] = L {\displaystyle L\in X\to \operatorname {sink-test} =L}
L X s i n k - t e s t [ L , X ] = sink [ L , X ] {\displaystyle L\not \in X\to \operatorname {sink-test} =\operatorname {sink} }

Example

Example of sinking

For example,

Rule Expression
de-let s i n k - t r a n [ d e - l e t [ let p   f   x = f   ( x   x ) q   p   f = ( p   f )   ( p   f ) in q   p ] ] {\displaystyle \operatorname {sink-tran} ]}
sink-tran s i n k - t r a n [ ( λ p . ( λ q . q   p )   ( λ p . λ f . ( p   f )   ( p   f ) ) )   ( λ f . λ x . f   ( x   x ) ) ] {\displaystyle \operatorname {sink-tran} }
Application
sink [ ( λ p . sink [ ( λ q . q   p )   ( λ p . λ f . ( p   f )   ( p   f ) ) ] )   ( λ f . λ x . f   ( x   x ) ) ] {\displaystyle \operatorname {sink} )\ (\lambda f.\lambda x.f\ (x\ x))]}
sink [ ( λ q . q   p )   ( λ p . λ f . ( p   f )   ( p   f ) ) ] {\displaystyle \operatorname {sink} }
E FV [ G ] E FV [ H ] sink [ ( λ E . G   H )   Y , X ] {\displaystyle E\in \operatorname {FV} \land E\not \in \operatorname {FV} \to \operatorname {sink} }
E = q , G = q , H = p , Y = ( λ p . λ f . ( p   f )   ( p   f ) ) , X = { } {\displaystyle E=q,G=q,H=p,Y=(\lambda p.\lambda f.(p\ f)\ (p\ f)),X=\{\}}
( sink [ ( λ E . G )   Y , X ] )   H {\displaystyle (\operatorname {sink} )\ H}
( sink [ ( λ q . q )   ( λ p . λ f . ( p   f )   ( p   f ) ) , X ] )   p {\displaystyle (\operatorname {sink} )\ p}
Variable
sink [ ( λ p . sink [ ( λ q . q )   ( λ p . λ f . ( p   f )   ( p   f ) ) ]   p )   ( λ f . λ x . f   ( x   x ) ) ] {\displaystyle \operatorname {sink} \ p)\ (\lambda f.\lambda x.f\ (x\ x))]}
sink [ ( λ q . q )   ( λ p . λ f . ( p   f )   ( p   f ) ) ] {\displaystyle \operatorname {sink} }
E = V sink [ ( λ E . V )   Y , X ] {\displaystyle E=V\to \operatorname {sink} }
E = q , V = q , Y = ( λ p . λ f . ( p   f )   ( p   f ) ) , X = { } {\displaystyle E=q,V=q,Y=(\lambda p.\lambda f.(p\ f)\ (p\ f)),X=\{\}}
Y {\displaystyle Y}
( λ p . λ f . ( p   f )   ( p   f ) ) {\displaystyle (\lambda p.\lambda f.(p\ f)\ (p\ f))}
Application
sink [ ( λ p . ( λ p . λ f . ( p   f )   ( p   f ) )   p )   ( λ f . λ x . f   ( x   x ) ) ] {\displaystyle \operatorname {sink} }
E FV [ G ] E FV [ H ] sink [ ( λ E . G   H )   Y , X ] {\displaystyle E\not \in \operatorname {FV} \land E\in \operatorname {FV} \to \operatorname {sink} }
E = p , G = ( λ p . λ f . ( p   f )   ( p   f ) ) , H = p , Y = ( λ f . λ x . f   ( x   x ) ) {\displaystyle E=p,G=(\lambda p.\lambda f.(p\ f)\ (p\ f)),H=p,Y=(\lambda f.\lambda x.f\ (x\ x))}
sink [ G   sink [ ( λ E . H )   Y , X ] ] {\displaystyle \operatorname {sink} ]}
Variable
sink [ ( λ p . λ f . ( p   f )   ( p   f ) )   s i n k - t e s t [ ( λ p . p )   ( λ f . λ x . f   ( x   x ) ) , X ] ] {\displaystyle \operatorname {sink} ]}
sink [ ( λ p . p )   ( λ f . λ x . f   ( x   x ) ) , X ] {\displaystyle \operatorname {sink} }
E = V sink [ ( λ E . V )   Y , X ] {\displaystyle E=V\to \operatorname {sink} }
E = p , V = p , Y = ( λ f . λ x . f   ( x   x ) ) , X = { } {\displaystyle E=p,V=p,Y=(\lambda f.\lambda x.f\ (x\ x)),X=\{\}}
Y {\displaystyle Y}
( λ f . λ x . f   ( x   x ) ) {\displaystyle (\lambda f.\lambda x.f\ (x\ x))}
Abstraction
sink [ ( λ p . λ f . ( p   f )   ( p   f ) )   ( λ f . λ x . f   ( x   x ) ) ] {\displaystyle \operatorname {sink} }
V W sink [ ( λ V . λ W . E )   Y , X ] {\displaystyle V\neq W\to \operatorname {sink} }
V = p , W = f , E = ( p   f )   ( p   f ) , Y = ( λ f . λ x . f   ( x   x ) ) {\displaystyle V=p,W=f,E=(p\ f)\ (p\ f),Y=(\lambda f.\lambda x.f\ (x\ x))}
λ W . sink [ ( λ V . E )   Y , X ] {\displaystyle \lambda W.\operatorname {sink} }
Application
λ f . sink [ ( λ p . ( p   f )   ( p   f ) )   ( λ f . λ x . f   ( x   x ) ) , X ] {\displaystyle \lambda f.\operatorname {sink} }
sink [ ( λ p . ( p   f )   ( p   f ) )   ( λ f . λ x . f   ( x   x ) ) , X ] {\displaystyle \operatorname {sink} }
E FV [ G ] E FV [ H ] sink [ ( λ E . G   H )   Y , X ] {\displaystyle E\in \operatorname {FV} \land E\in \operatorname {FV} \to \operatorname {sink} }
E = p , G = ( p   f ) , H = ( p   f ) , Y = ( λ f . λ x . f   ( x   x ) ) {\displaystyle E=p,G=(p\ f),H=(p\ f),Y=(\lambda f.\lambda x.f\ (x\ x))}
( λ E . G   H )   Y {\displaystyle (\lambda E.G\ H)\ Y}
( λ p . ( p   f )   ( p   f ) )   ( λ f . λ x . f   ( x   x ) ) {\displaystyle (\lambda p.(p\ f)\ (p\ f))\ (\lambda f.\lambda x.f\ (x\ x))}
λ f . ( λ p . ( p   f )   ( p   f ) )   ( λ f . λ x . f   ( x   x ) ) {\displaystyle \lambda f.(\lambda p.(p\ f)\ (p\ f))\ (\lambda f.\lambda x.f\ (x\ x))}

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 are 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,

λ m , p , q . ( λ g . λ n . ( n   ( g   m   p   n )   ( g   q   p   n ) ) )   λ x . λ o . λ y . o   x   y {\displaystyle \lambda m,p,q.(\lambda g.\lambda n.(n\ (g\ m\ p\ n)\ (g\ q\ p\ n)))\ \lambda x.\lambda o.\lambda y.o\ x\ y}

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,

d r o p - p a r a m s - t r a n [ λ m , p , q . ( λ g . λ n . n   ( g   m   p   n )   ( g   q   p   n ) )   λ x . λ o . λ y . o   x   y {\displaystyle \operatorname {drop-params-tran} [\lambda m,p,q.(\lambda g.\lambda n.n\ (g\ m\ p\ n)\ (g\ q\ p\ n))\ \lambda x.\lambda o.\lambda y.o\ x\ y}
λ m , p , q . ( λ g . λ n . n   ( g   m   n )   ( g   q   n ) )   λ x . λ y . p   x   y {\displaystyle \equiv \lambda m,p,q.(\lambda g.\lambda n.n\ (g\ m\ n)\ (g\ q\ n))\ \lambda x.\lambda y.p\ x\ y}

For the main example,

d r o p - p a r a m s - t r a n [ λ f . ( λ p . ( p   f )   ( p   f ) )   ( λ f . λ x . f   ( x   x ) ) ] {\displaystyle \operatorname {drop-params-tran} }
λ f . ( λ p . p   p )   ( λ x . f   ( x   x ) ) {\displaystyle \equiv \lambda f.(\lambda p.p\ p)\ (\lambda x.f\ (x\ x))}

The definition of drop-params-tran is,

d r o p - p a r a m s - t r a n [ L ] ( d r o p - p a r a m s [ L , D , F V [ L ] , [ ] ] ) {\displaystyle \operatorname {drop-params-tran} \equiv (\operatorname {drop-params} ,])}

where,

b u i l d - p a r a m - l i s t [ L , D , V , _ ] {\displaystyle \operatorname {build-param-list} }

Build parameter lists

For each abstraction that defines a function, build the information required to make decisions on dropping names. This information describes 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,

λ m , p , q . ( λ g . λ n . ( n   ( g   m   p   n )   ( g   q   p   n ) ) )   λ x . λ o . λ y . o   x   y {\displaystyle \lambda m,p,q.(\lambda g.\lambda n.(n\ (g\ m\ p\ n)\ (g\ q\ p\ n)))\ \lambda x.\lambda o.\lambda y.o\ x\ y}

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, g there is parameter list.

D [ g ] = [ [ x , false , _ ] , [ o , _ , p ] , [ y , _ , n ] ] {\displaystyle D=,,]}

build-param-lists builds all the lists for an expression, by traversing the expression. It has four parameters;

  • The lambda expression being analyzed.
  • The table parameter lists for names.
  • The table of values for parameters.
  • The returned parameter list, which is used internally by the

Abstraction - A lambda expression of the form ( λ N . S )   L {\displaystyle (\lambda N.S)\ L} is analyzed to extract the names of parameters for the function.

{ b u i l d - p a r a m - l i s t s [ ( λ N . S )   L , D , V , R ] b u i l d - p a r a m - l i s t s [ S , D , V , R ] b u i l d - l i s t [ L , D , V , D [ N ] ] b u i l d - p a r a m - l i s t s [ λ N . S , D , V , R ] b u i l d - p a r a m - l i s t s [ S , D , V , R ] {\displaystyle {\begin{cases}\operatorname {build-param-lists} \equiv \operatorname {build-param-lists} \land \operatorname {build-list} ]\\\operatorname {build-param-lists} \equiv \operatorname {build-param-lists} \end{cases}}}

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

{ b u i l d - l i s t [ λ P . B , D , V , [ X , _ , _ ] :: L ] b u i l d - l i s t [ B , D , V , L ] b u i l d - l i s t [ B , D , V , [ ] ] b u i l d - p a r a m - l i s t s [ B , D , V , _ ] {\displaystyle {\begin{cases}\operatorname {build-list} ::L]\equiv \operatorname {build-list} \\\operatorname {build-list} ]\equiv \operatorname {build-param-lists} \end{cases}}}

Variable - A call to a function.

b u i l d - p a r a m - l i s t s [ N , D , V , D [ N ] ] {\displaystyle \operatorname {build-param-lists} ]}

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 actual parameter details.

b u i l d - p a r a m - l i s t s [ E   P , D , V , R ] b u i l d - p a r a m - l i s t s [ E , D , V , T ] b u i l d - p a r a m - l i s t s [ P , D , V , K ] {\displaystyle \operatorname {build-param-lists} \equiv \operatorname {build-param-lists} \land \operatorname {build-param-lists} }
T = [ F , S , A ] :: R ( S ( equate [ A , P ] V [ F ] = A ) ) D [ F ] = K {\displaystyle \land T=::R\land (S\implies (\operatorname {equate} \land V=A))\land D=K}

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.

{ equate [ A , N ] A = N ( def [ V [ N ] ] A = V [ N ] ) if  N  is a variable. equate [ A , E ] A = E otherwise. {\displaystyle {\begin{cases}\operatorname {equate} \equiv A=N\lor (\operatorname {def} ]\land A=V)&{\text{if }}N{\text{ is a variable.}}\\\operatorname {equate} \equiv A=E&{\text{otherwise.}}\end{cases}}}

The above logic is quite subtle in the way that it works. 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.

ask [ S ] S { X : X = S } {\displaystyle \operatorname {ask} \equiv S\in \{X:X=S\}}

Similarly, def uses set theory to query if a variable has been given a value;

def [ F ] | { X : X = F } | {\displaystyle \operatorname {def} \equiv |\{X:X=F\}|}

Let - Let expression.

b u i l d - p a r a m - l i s t [ let V : E in L , D , V , _ ] b u i l d - p a r a m - l i s t [ E , D , V , _ ] b u i l d - p a r a m - l i s t [ L , D , V , _ ] {\displaystyle \operatorname {build-param-list} \equiv \operatorname {build-param-list} \land \operatorname {build-param-list} }

And - For use in "let".

b u i l d - p a r a m - l i s t s [ E F , D , V , _ ] b u i l d - p a r a m - l i s t s [ E , D , V , _ ] b u i l d - p a r a m - l i s t s [ F , D , V , _ ] {\displaystyle \operatorname {build-param-lists} \equiv \operatorname {build-param-lists} \land \operatorname {build-param-lists} }
Examples

For example, building the parameter lists for,

λ m , p , q . ( λ g . λ n . ( n   ( g   m   p   n )   ( g   q   p   n ) ) )   λ x . λ o . λ y . o   x   y {\displaystyle \lambda m,p,q.(\lambda g.\lambda n.(n\ (g\ m\ p\ n)\ (g\ q\ p\ n)))\ \lambda x.\lambda o.\lambda y.o\ x\ y}

gives,

D [ g ] = [ [ x , false , _ ] , [ o , true , p ] , [ y , true , n ] ] {\displaystyle D=,,]}

and the parameter o is dropped to give,

λ m , p , q . ( λ g . λ n . ( n   ( g   m   n )   ( g   q   n ) ) )   λ x . λ y . p   x   y {\displaystyle \lambda m,p,q.(\lambda g.\lambda n.(n\ (g\ m\ n)\ (g\ q\ n)))\ \lambda x.\lambda y.p\ x\ y}
Build parameter list for λ m , p , q . ( λ g . λ n . ( n   ( g   m   p   n )   ( g   q   p   n ) ) )   λ x . λ o . λ y . o   x   y {\displaystyle \lambda m,p,q.(\lambda g.\lambda n.(n\ (g\ m\ p\ n)\ (g\ q\ p\ n)))\ \lambda x.\lambda o.\lambda y.o\ x\ y}
Build parameter list example
b u i l d - p a r a m - l i s t [ λ m , p , q . ( λ g . λ n . ( n   ( g   m   p   n )   ( g   q   p   n ) ) )   λ x . λ o . λ y . o   x   y , D , V , _ ] {\displaystyle \operatorname {build-param-list} }
Rule Expression
Abstraction b u i l d - p a r a m - l i s t [ λ m , p , q . ( λ g . λ n . ( n   ( g   m   p   n )   ( g   q   p   n ) ) )   λ x . λ o . λ y . o   x   y , D , V , _ ] {\displaystyle \operatorname {build-param-list} }
Abstraction b u i l d - p a r a m - l i s t [ ( λ g . λ n . ( n   ( g   m   p   n )   ( g   q   p   n ) ) )   λ x . λ o . λ y . o   x   y , D , V , _ ] {\displaystyle \operatorname {build-param-list} }
b u i l d - p a r a m - l i s t s [ n   ( g   m   p   n )   ( g   q   p   n ) , D , V , R ] b u i l d - l i s t [ λ x . λ o . λ y . o   x   y , D , V , D [ g ] ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-list} ]}
b u i l d - l i s t [ λ x . λ o . λ y . o   x   y , D , V , D [ g ] ] {\displaystyle \operatorname {build-list} ]}
Rule Expression
Add param

b u i l d - l i s t [ λ x . λ o . λ y . o   x   y , D , V , D [ g ] ] D [ g ] = L 1 {\displaystyle \operatorname {build-list} ]\land D=L_{1}}

Add param

b u i l d - l i s t [ λ o . λ y . o   x   y , D , V , L 1 ] D [ g ] = [ x , _ , _ ] :: L 1 {\displaystyle \operatorname {build-list} \land D=::L_{1}}

Add param

b u i l d - l i s t [ λ y . o   x   y , D , V , L 2 ] D [ g ] = [ x , _ , _ ] :: [ o , _ , _ ] :: L 2 {\displaystyle \operatorname {build-list} \land D=::::L_{2}}

End list b u i l d - l i s t [ o   x   y , D , V , L 3 ] D [ g ] = [ x , _ , _ ] :: [ o , _ , _ ] :: [ y , _ , _ ] :: L 3 {\displaystyle \operatorname {build-list} \land D=::::::L_{3}}
b u i l d - p a r a m - l i s t s [ o   x   y , D , V , [ ] ] D [ g ] = [ x , _ , _ ] :: [ o , _ , _ ] :: [ y , _ , _ ] :: [ ] {\displaystyle \operatorname {build-param-lists} ]\land D=::::::}
b u i l d - p a r a m - l i s t s [ n   ( g   m   p   n )   ( g   q   p   n ) , D , V , R ] {\displaystyle \operatorname {build-param-lists} }
Rule Expression
Application b u i l d - p a r a m - l i s t s [ n   ( g   m   p   n )   ( g   q   p   n ) , D , V , R ] {\displaystyle \operatorname {build-param-lists} }
Application

b u i l d - p a r a m - l i s t s [ n   ( g   m   p   n ) , D , V , T 1 ] b u i l d - p a r a m - l i s t s [ g   q   p   n , D , V , K 1 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} }

( ( T 1 = [ F 1 , S 1 , A 1 ] :: R {\displaystyle \land ((T_{1}=::R}
( S 1 ( equate [ A 1 , g   q   p   n ] V [ F 1 ] = g   q   p   n ) ) D [ F 1 ] = K 1 ) {\displaystyle \land (S_{1}\implies (\operatorname {equate} \land V=g\ q\ p\ n))\land D=K_{1})}
Variable

b u i l d - p a r a m - l i s t s [ n , D , V , T 2 ] b u i l d - p a r a m - l i s t s [ g   m   p   n , D , V , K 2 ] b u i l d - p a r a m - l i s t s [ g   q   p   n , D , V , K 1 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} \land \operatorname {build-param-lists} }

( ( T 2 = [ F 2 , S 2 , A 2 ] :: [ F 1 , S 1 , A 1 ] :: R {\displaystyle \land ((T_{2}=::::R}
( S 1 ( equate [ A 1 , g   q   p   n ] V [ F 1 ] = g   q   p   n ) ) D [ F 1 ] = K 1 ) {\displaystyle \land (S_{1}\implies (\operatorname {equate} \land V=g\ q\ p\ n))\land D=K_{1})}
( S 2 ( equate [ A 2 , g   m   p   n ] V [ F 2 ] = g   m   p   n ) ) D [ F 2 ] = K 2 ) {\displaystyle \land (S_{2}\implies (\operatorname {equate} \land V=g\ m\ p\ n))\land D=K_{2})}
Variable

b u i l d - p a r a m - l i s t s [ g   m   p   n , D , V , K 2 ] b u i l d - p a r a m - l i s t s [ g   q   p   n , D , V , K 1 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} }

( ( D [ n ] = [ F 2 , S 2 , A 2 ] :: [ F 1 , S 1 , A 1 ] :: R {\displaystyle \land ((D=::::R}
( S 1 ( equate [ A 1 , g   q   p   n ] V [ F 1 ] = g   q   p   n ) ) D [ F 1 ] = K 1 ) {\displaystyle \land (S_{1}\implies (\operatorname {equate} \land V=g\ q\ p\ n))\land D=K_{1})}
( S 2 ( equate [ A 2 , g   m   p   n ] V [ F 2 ] = g   m   p   n ) ) D [ F 2 ] = K 2 ) {\displaystyle \land (S_{2}\implies (\operatorname {equate} \land V=g\ m\ p\ n))\land D=K_{2})}

Gives,

D [ n ] = [ _ , _ , g   m   p   n ] :: [ _ , _ , g   q   p   n ] :: R {\displaystyle D=::::R}
b u i l d - p a r a m - l i s t s [ g   m   p   n , D , V , K 2 ] {\displaystyle \operatorname {build-param-lists} }
Rule Expression
application

b u i l d - p a r a m - l i s t s [ g   m   p   n , D , V , K 2 ] {\displaystyle \operatorname {build-param-lists} }

b u i l d - p a r a m - l i s t s [ g   m   p , D , V , T 3 ] b u i l d - p a r a m - l i s t s [ n , D , V , K 3 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} }

( ( T 3 = [ F 3 , S 3 , A 3 ] :: K 2 {\displaystyle \land ((T_{3}=::K_{2}}
( S 3 ( equate [ A 3 , n ] V [ F 3 ] = n ) ) D [ F 3 ] = D [ n ] ) {\displaystyle \land (S_{3}\implies (\operatorname {equate} \land V=n))\land D=D)}
application, Variable

b u i l d - p a r a m - l i s t s [ g   m , D , V , T 4 ] b u i l d - p a r a m - l i s t s [ p , D , V , K 4 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} }

T 4 = [ _ , S 4 , A 4 ] :: [ _ , S 3 , A 3 ] :: K 2 {\displaystyle \land T_{4}=::::K_{2}}
( S 3 ( equate [ A 3 , n ] V [ F 3 ] = n ) ) D [ F 3 ] = D [ n ] ) {\displaystyle \land (S_{3}\implies (\operatorname {equate} \land V=n))\land D=D)}
( S 4 ( equate [ A 4 , p ] V [ F 4 ] = p ) ) D [ F 4 ] = D [ p ] {\displaystyle \land (S_{4}\implies (\operatorname {equate} \land V=p))\land D=D}
application, Variable

b u i l d - p a r a m - l i s t s [ g , D , V , T 5 ] b u i l d - p a r a m - l i s t s [ m , D , V , K 5 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} }

T 5 = [ F 5 , S 5 , A 5 ] :: [ F 4 , S 4 , A 4 ] :: [ F 3 , S 3 , A 3 ] :: K 2 {\displaystyle \land T_{5}=::::::K_{2}}
( S 3 ( equate [ A 3 , n ] V [ F 3 ] = n ) ) D [ F 3 ] = D [ n ] ) {\displaystyle \land (S_{3}\implies (\operatorname {equate} \land V=n))\land D=D)}
( S 4 ( equate [ A 4 , p ] V [ F 4 ] = p ) ) D [ F 4 ] = D [ p ] {\displaystyle \land (S_{4}\implies (\operatorname {equate} \land V=p))\land D=D}
( S 5 ( equate [ A 5 , m ] V [ F 5 ] = m ) ) D [ F 5 ] = D [ m ] {\displaystyle \land (S_{5}\implies (\operatorname {equate} \land V=m))\land D=D}
Variable

D [ g ] = [ x , S 5 , A 5 ] :: [ o , S 4 , A 4 ] :: [ y , S 3 , A 3 ] :: K 2 {\displaystyle D=::::::K_{2}}

( S 3 ( equate [ A 3 , n ] V [ y ] = n ) ) D [ y ] = D [ n ] ) {\displaystyle \land (S_{3}\implies (\operatorname {equate} \land V=n))\land D=D)}
( S 4 ( equate [ A 4 , p ] V [ o ] = p ) ) D [ o ] = D [ p ] {\displaystyle \land (S_{4}\implies (\operatorname {equate} \land V=p))\land D=D}
( S 5 ( equate [ A 5 , m ] V [ x ] = m ) ) D [ x ] = D [ m ] {\displaystyle \land (S_{5}\implies (\operatorname {equate} \land V=m))\land D=D}
b u i l d - p a r a m - l i s t s [ g   q   p   n , D , V , K 1 ] {\displaystyle \operatorname {build-param-lists} }
Rule Expression
application

b u i l d - p a r a m - l i s t s [ g   q   p   n , D , V , K 1 ] {\displaystyle \operatorname {build-param-lists} }

b u i l d - p a r a m - l i s t s [ g   q   p , D , V , T 6 ] b u i l d - p a r a m - l i s t s [ n , D , V , K 6 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} }

( ( T 6 = [ F 6 , S 6 , A 6 ] :: K 1 {\displaystyle \land ((T_{6}=::K_{1}}
( S 6 ( equate [ A 6 , n ] V [ F 6 ] = n ) ) D [ F 6 ] = D [ n ] ) {\displaystyle \land (S_{6}\implies (\operatorname {equate} \land V=n))\land D=D)}
application, Variable

b u i l d - p a r a m - l i s t s [ g   q , D , V , T 7 ] b u i l d - p a r a m - l i s t s [ p , D , V , K 7 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} }

T 7 = [ _ , S 7 , A 7 ] :: [ _ , S 6 , A 6 ] :: K 1 {\displaystyle \land T_{7}=::::K_{1}}
( S 6 ( equate [ A 6 , n ] V [ F 6 ] = n ) ) D [ F 6 ] = D [ n ] ) {\displaystyle \land (S_{6}\implies (\operatorname {equate} \land V=n))\land D=D)}
( S 7 ( equate [ A 7 , p ] V [ F 7 ] = p ) ) D [ F 7 ] = D [ p ] {\displaystyle \land (S_{7}\implies (\operatorname {equate} \land V=p))\land D=D}
application, Variable

b u i l d - p a r a m - l i s t s [ g , D , V , T 8 ] b u i l d - p a r a m - l i s t s [ m , D , V , K 8 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} }

T 8 = [ F 8 , S 8 , A 8 ] :: [ F 7 , S 7 , A 7 ] :: [ F 6 , S 6 , A 6 ] :: K 1 {\displaystyle \land T_{8}=::::::K_{1}}
( S 6 ( equate [ A 6 , n ] V [ F 6 ] = n ) ) D [ F 6 ] = D [ n ] ) {\displaystyle \land (S_{6}\implies (\operatorname {equate} \land V=n))\land D=D)}
( S 7 ( equate [ A 7 , p ] V [ F 7 ] = p ) ) D [ F 7 ] = D [ p ] {\displaystyle \land (S_{7}\implies (\operatorname {equate} \land V=p))\land D=D}
( S 8 ( equate [ A 8 , q ] V [ F 8 ] = q ) ) D [ F 8 ] = D [ q ] {\displaystyle \land (S_{8}\implies (\operatorname {equate} \land V=q))\land D=D}
Variable

D [ g ] = [ x , S 8 , A 8 ] :: [ o , S 6 , A 7 ] :: [ y , S 6 , A 6 ] :: K 1 {\displaystyle D=::::::K_{1}}

( S 6 ( equate [ A 6 , n ] V [ y ] = n ) ) D [ y ] = D [ n ] ) {\displaystyle \land (S_{6}\implies (\operatorname {equate} \land V=n))\land D=D)}
( S 7 ( equate [ A 7 , p ] V [ o ] = p ) ) D [ o ] = D [ p ] {\displaystyle \land (S_{7}\implies (\operatorname {equate} \land V=p))\land D=D}
( S 8 ( equate [ A 8 , q ] V [ x ] = q ) ) D [ x ] = D [ q ] {\displaystyle \land (S_{8}\implies (\operatorname {equate} \land V=q))\land D=D}

As there are no definitions for, V [ n ] , V [ p ] , V [ q ] , V [ m ] {\displaystyle V,V,V,V} , then equate can be simplified to,

equate [ A , N ] A = N ( def [ V [ N ] ] A = V [ N ] ) A = N {\displaystyle \operatorname {equate} \equiv A=N\lor (\operatorname {def} ]\land A=V)\equiv A=N}

By removing expressions not needed, D [ g ] = [ x , S 5 , A 5 ] :: [ o , S 4 , A 4 ] :: [ y , S 3 , A 3 ] :: K 2 {\displaystyle D=::::::K_{2}}

S 3 A 3 = n {\displaystyle \land S_{3}\implies A_{3}=n}
S 4 A 4 = p {\displaystyle \land S_{4}\implies A_{4}=p}
S 5 A 5 = m {\displaystyle \land S_{5}\implies A_{5}=m}

D [ g ] = [ x , S 8 , A 8 ] :: [ o , S 6 , A 7 ] :: [ y , S 6 , A 6 ] :: K 1 {\displaystyle D=::::::K_{1}}

S 6 A 6 = n {\displaystyle \land S_{6}\implies A_{6}=n}
S 7 A 7 = p {\displaystyle \land S_{7}\implies A_{7}=p}
S 8 A 8 = q {\displaystyle \land S_{8}\implies A_{8}=q}

By comparing the two expressions for D [ g ] {\displaystyle D} , get,

S 5 = S 8 , A 5 = A 8 , S 4 = S 7 , A 4 = A 7 , S 3 = S 6 , A 3 = A 6 {\displaystyle S_{5}=S_{8},A_{5}=A_{8},S_{4}=S_{7},A_{4}=A_{7},S_{3}=S_{6},A_{3}=A_{6}}

If S 3 {\displaystyle S_{3}} is true;

n = A 3 = A 6 = n {\displaystyle n=A_{3}=A_{6}=n}

If S 3 {\displaystyle S_{3}} is false there is no implication. So S 3 = _ {\displaystyle S_{3}=\_} which means it may be true or false.

If S 4 {\displaystyle S_{4}} is true;

p = A 4 = A 7 = p {\displaystyle p=A_{4}=A_{7}=p}

If S 5 {\displaystyle S_{5}} is true;

m = A 5 = A 8 = q {\displaystyle m=A_{5}=A_{8}=q}

So S 5 {\displaystyle S_{5}} is false.

The result is, D [ g ] = [ x , false , _ ] :: [ o , _ , p ] :: [ y , _ , n ] :: _ {\displaystyle D=::::::\_}

b u i l d - p a r a m - l i s t s [ o   x   y , D , V , L ] {\displaystyle \operatorname {build-param-lists} }
Rule Expression
application b u i l d - p a r a m - l i s t s [ o   x   y , D , V , L ] {\displaystyle \operatorname {build-param-lists} }
application

b u i l d - p a r a m - l i s t s [ o   x , D , V , T 9 ] b u i l d - p a r a m - l i s t s [ y , D , V , K 9 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} }

T 9 = [ F 9 , S 9 , A 9 ] :: L {\displaystyle \land T_{9}=::L}
( S 9 ( equate [ A 9 , y ] V [ F 9 ] = A 9 ) K 9 = D [ F 9 ] {\displaystyle \land (S_{9}\implies (\operatorname {equate} \land V=A_{9})\land K_{9}=D}
variable

b u i l d - p a r a m - l i s t s [ o , D , V , T 10 ] b u i l d - p a r a m - l i s t s [ x , D , V , K 10 ] b u i l d - p a r a m - l i s t s [ y , D , V , K 10 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} \land \operatorname {build-param-lists} }

T 10 = [ F 10 , S 10 , A 10 ] :: [ F 9 , S 9 , A 9 ] :: L {\displaystyle \land T_{10}=::::L}
( S 9 ( equate [ A 9 , y ] V [ F 9 ] = A 9 ) K 9 = D [ F 9 ] {\displaystyle \land (S_{9}\implies (\operatorname {equate} \land V=A_{9})\land K_{9}=D}
( S 10 ( equate [ A 10 , y ] V [ F 10 ] = A 10 ) K 10 = D [ F 10 ] {\displaystyle \land (S_{10}\implies (\operatorname {equate} \land V=A_{10})\land K_{10}=D}
D [ o ] = [ F 10 , S 10 , A 10 ] :: [ F 9 , S 9 , A 9 ] :: L {\displaystyle \land D=::::L}
( S 9 ( equate [ A 9 , y ] V [ F 9 ] = A 9 ) K 9 = D [ F 9 ] {\displaystyle \land (S_{9}\implies (\operatorname {equate} \land V=A_{9})\land K_{9}=D}
( S 10 ( equate [ A 10 , y ] V [ F 10 ] = A 10 ) K 10 = D [ F 10 ] {\displaystyle \land (S_{10}\implies (\operatorname {equate} \land V=A_{10})\land K_{10}=D}

By similar arguments as used above get,

D [ o ] = [ _ , _ , x ] :: [ _ , _ , y ] :: _ {\displaystyle D=::::\_}

and from previously,

D [ g ] = [ [ x , false , _ ] , [ o , true , p ] , [ y , true , n ] ] {\displaystyle D=,,]}
D [ n ] = [ [ _ , _ , ( g   m   p   n ) ] , [ _ , _ , ( g   q   p   n ) ] ] {\displaystyle D=,]}
D [ m ] = _ {\displaystyle D=\_}
D [ p ] = _ {\displaystyle D=\_}
D [ q ] = _ {\displaystyle D=\_}

Another example is,

λ f . ( ( λ p . f   ( p   p   f ) )   ( λ q . λ x . x   ( q   q   x ) ) {\displaystyle \lambda f.((\lambda p.f\ (p\ p\ f))\ (\lambda q.\lambda x.x\ (q\ q\ x))}

Here x is equal to f. The parameter list mapping is,

D [ p ] = [ [ q , _ , p ] , [ x , _ , f ] ] {\displaystyle D=,]}

and the parameter x is dropped to give,

λ f . ( ( λ q . f   ( q   q ) )   ( λ q . f   ( q   q ) ) {\displaystyle \lambda f.((\lambda q.f\ (q\ q))\ (\lambda q.f\ (q\ q))}
Build parameter list for λ f . ( ( λ p . f   ( p   p   f ) )   ( λ q . λ x . x   ( q   q   x ) ) {\displaystyle \lambda f.((\lambda p.f\ (p\ p\ f))\ (\lambda q.\lambda x.x\ (q\ q\ x))}

The logic in equate is used in this more difficult example.

b u i l d - p a r a m - l i s t [ λ f . ( ( λ p . f   ( p   p   f ) )   ( λ q . λ x . x   ( q   q   x ) ) , D , V , _ ] {\displaystyle \operatorname {build-param-list} }
Rule Expression
Abstraction b u i l d - p a r a m - l i s t [ λ f . ( ( λ p . f   ( p   p   f ) )   ( λ q . λ x . x   ( q   q   x ) ) , D , V , _ ] {\displaystyle \operatorname {build-param-list} }
Abstraction b u i l d - p a r a m - l i s t [ ( λ p . f   ( p   p   f ) )   ( λ q . λ x . x   ( q   q   x ) ) , D , V , _ ] {\displaystyle \operatorname {build-param-list} }
b u i l d - p a r a m - l i s t s [ f   ( p   p   f ) , D , _ ] b u i l d - l i s t [ λ q . λ x . x   ( q   q   x ) , D , D [ p ] ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-list} ]}
b u i l d - p a r a m - l i s t s [ f   ( p   p   f ) , D , _ ] b u i l d - l i s t [ λ q . λ x . x   ( q   q   x ) , D , D [ p ] ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-list} ]}
b u i l d - l i s t [ λ q . λ x . x   ( q   q   x ) , D , D [ p ] ] {\displaystyle \operatorname {build-list} ]}
Rule Expression
Add param b u i l d - l i s t [ λ q . λ x . x   ( q   q   x ) , D , D [ p ] ] D [ p ] = L 1 {\displaystyle \operatorname {build-list} ]\land D=L_{1}}
Add param b u i l d - l i s t [ λ x . x   ( q   q   x ) , D , L 2 ] D [ p ] = [ q , _ , _ ] :: L 2 {\displaystyle \operatorname {build-list} \land D=::L_{2}}
End list b u i l d - l i s t [ x   ( q   q   x ) , D , L 3 ] D [ p ] = [ q , _ , _ ] :: [ x , _ , _ ] :: L 3 {\displaystyle \operatorname {build-list} \land D=::::L_{3}}
b u i l d - p a r a m - l i s t s [ x   ( q   q   x ) , D , [ ] ] D [ p ] = [ q , _ , _ ] :: [ x , _ , _ ] :: [ ] {\displaystyle \operatorname {build-param-lists} ]\land D=::::}
b u i l d - p a r a m - l i s t s [ λ p . f   ( p   p   f ) , D , V , T 1 ] {\displaystyle \operatorname {build-param-lists} }
Rule Expression
Abstraction b u i l d - p a r a m - l i s t s [ λ p . f   ( p   p   f ) , D , V , T 1 ] {\displaystyle \operatorname {build-param-lists} }
Application b u i l d - p a r a m - l i s t s [ f   ( p   p   f ) , D , V , T 1 ] {\displaystyle \operatorname {build-param-lists} }
Name b u i l d - p a r a m - l i s t s [ f , D , V , T 2 ] b u i l d - p a r a m - l i s t s [ p   p   f , D , V , K 2 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} }
T 2 = [ F 2 , S 2 , A 2 ] :: [ F 1 , S 1 , A 1 ] :: _ {\displaystyle \land T_{2}=::::\_}
( S 2 ( equate [ A 2 , p   p   f ] V [ F 2 ] = A 2 ) ) D [ F 2 ] = K 2 {\displaystyle \land (S_{2}\implies (\operatorname {equate} \land V=A_{2}))\land D=K_{2}}
Name b u i l d - p a r a m - l i s t s [ p   p   f , D , V , K 2 ] {\displaystyle \operatorname {build-param-lists} }

D [ f ] = [ F 2 , S 2 , A 2 ] :: [ F 1 , S 1 , A 1 ] :: _ {\displaystyle \land D=::::\_}

( S 2 ( equate [ A 2 , p   p   f ] V [ F 2 ] = A 2 ) ) D [ F 2 ] = K 2 {\displaystyle \land (S_{2}\implies (\operatorname {equate} \land V=A_{2}))\land D=K_{2}}
Name b u i l d - p a r a m - l i s t s [ p   p , D , V , T 3 ] b u i l d - p a r a m - l i s t s [ f , D , V , K 3 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} }
T 3 = [ F 3 , S 3 , A 3 ] :: K 2 {\displaystyle \land T_{3}=::K_{2}}
( S 3 ( equate [ A 3 , f ] V [ F 3 ] = A 3 ) ) D [ F 3 ] = K 3 {\displaystyle \land (S_{3}\implies (\operatorname {equate} \land V=A_{3}))\land D=K_{3}}
Application b u i l d - p a r a m - l i s t s [ p   p , D , V , T 3 ] {\displaystyle \operatorname {build-param-lists} }
T 3 = [ F 3 , S 3 , A 3 ] :: K 2 {\displaystyle \land T_{3}=::K_{2}}
( S 2 ( equate [ A 2 , p   p   f ] V [ F 2 ] = A 2 ) ) D [ F 2 ] = K 2 {\displaystyle \land (S_{2}\implies (\operatorname {equate} \land V=A_{2}))\land D=K_{2}}
( S 3 ( equate [ A 3 , f ] V [ F 3 ] = A 3 ) ) D [ F 3 ] = D [ f ] {\displaystyle \land (S_{3}\implies (\operatorname {equate} \land V=A_{3}))\land D=D}
Name b u i l d - p a r a m - l i s t s [ p , D , V , T 4 ] b u i l d - p a r a m - l i s t s [ p , D , V , K 4 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} }
T 4 = [ F 4 , S 4 , A 4 ] :: [ F 3 , S 3 , A 3 ] :: K 2 {\displaystyle \land T_{4}=::::K_{2}}
( S 3 ( equate [ A 3 , f ] V [ F 3 ] = A 3 ) ) D [ F 3 ] = D [ f ] {\displaystyle \land (S_{3}\implies (\operatorname {equate} \land V=A_{3}))\land D=D}
( S 4 ( equate [ A 4 , p ] V [ F 4 ] = A 4 ) ) D [ F 4 ] = K 4 {\displaystyle \land (S_{4}\implies (\operatorname {equate} \land V=A_{4}))\land D=K_{4}}
D [ p ] = [ F 4 , S 4 , A 4 ] :: [ F 3 , S 3 , A 3 ] :: K 2 {\displaystyle D=::::K_{2}}
( S 3 ( equate [ A 3 , f ] V [ F 3 ] = A 3 ) ) D [ F 3 ] = D [ f ] {\displaystyle \land (S_{3}\implies (\operatorname {equate} \land V=A_{3}))\land D=D}
( S 4 ( equate [ A 4 , p ] V [ F 4 ] = A 4 ) ) D [ F 4 ] = D [ p ] {\displaystyle \land (S_{4}\implies (\operatorname {equate} \land V=A_{4}))\land D=D}
b u i l d - p a r a m - l i s t s [ x   ( q   q   x ) ) , D , V , _ ] {\displaystyle \operatorname {build-param-lists} }
Rule Expression
Abstraction b u i l d - p a r a m - l i s t s [ λ q . λ x . x   ( q   q   x ) ) , D , V , _ ] {\displaystyle \operatorname {build-param-lists} }
Application b u i l d - p a r a m - l i s t s [ x   ( q   q   x ) ) , D , V , K 1 ] {\displaystyle \operatorname {build-param-lists} }
Name b u i l d - p a r a m - l i s t s [ x , D , V , T 5 ] b u i l d - p a r a m - l i s t s [ q   q   x , D , V , K 5 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} }
T 5 = [ F 5 , S 5 , A 5 ] :: _ {\displaystyle \land T_{5}=::\_}
( S 5 ( equate [ A 5 , q   q   x ] V [ F 5 ] = A 5 ) ) D [ F 5 ] = K 5 {\displaystyle \land (S_{5}\implies (\operatorname {equate} \land V=A_{5}))\land D=K_{5}}
Name b u i l d - p a r a m - l i s t s [ q   q   x , D , V , K 5 ] {\displaystyle \operatorname {build-param-lists} }
D [ x ] = [ F 5 , S 5 , A 5 ] :: _ {\displaystyle \land D=::\_}
( S 5 ( equate [ A 5 , q   q   x ] V [ F 5 ] = A 5 ) ) D [ F 5 ] = K 5 {\displaystyle \land (S_{5}\implies (\operatorname {equate} \land V=A_{5}))\land D=K_{5}}
Name b u i l d - p a r a m - l i s t s [ q   q , D , V , T 6 ] b u i l d - p a r a m - l i s t s [ x , D , V , K 6 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} }
T 6 = [ F 6 , S 6 , A 6 ] :: K 5 {\displaystyle \land T_{6}=::K_{5}}
( S 6 ( equate [ A 6 , x ] V [ F 6 ] = A 6 ) ) D [ F 6 ] = K 6 {\displaystyle \land (S_{6}\implies (\operatorname {equate} \land V=A_{6}))\land D=K_{6}}
Application b u i l d - p a r a m - l i s t s [ q   q , D , V , T 6 ] {\displaystyle \operatorname {build-param-lists} }
T 6 = [ F 6 , S 6 , A 6 ] :: K 5 {\displaystyle \land T_{6}=::K_{5}}
( S 6 ( equate [ A 6 , x ] V [ F 6 ] = A 6 ) ) D [ F 6 ] = D [ x ] {\displaystyle \land (S_{6}\implies (\operatorname {equate} \land V=A_{6}))\land D=D}
Name b u i l d - p a r a m - l i s t s [ q , D , V , T 7 ] b u i l d - p a r a m - l i s t s [ q , D , V , K 7 ] {\displaystyle \operatorname {build-param-lists} \land \operatorname {build-param-lists} }
T 7 = [ F 7 , S 7 , A 7 ] :: [ F 6 , S 6 , A 6 ] :: K 5 {\displaystyle \land T_{7}=::::K_{5}}
( S 6 ( equate [ A 6 , x ] V [ F 6 ] = A 6 ) ) D [ F 6 ] = D [ x ] {\displaystyle \land (S_{6}\implies (\operatorname {equate} \land V=A_{6}))\land D=D}
( S 7 ( equate [ A 7 , q ] V [ F 7 ] = A 7 ) ) D [ F 7 ] = K 7 {\displaystyle \land (S_{7}\implies (\operatorname {equate} \land V=A_{7}))\land D=K_{7}}
Name b u i l d - p a r a m - l i s t s [ q , D , V , K 7 ] {\displaystyle \operatorname {build-param-lists} }
D [ q ] = [ F 7 , S 7 , A 7 ] :: [ F 6 , S 6 , A 6 ] :: K 5 {\displaystyle \land D=::::K_{5}}
( S 6 ( equate [ A 6 , x ] V [ F 6 ] = A 6 ) ) D [ F 6 ] = D [ x ] {\displaystyle \land (S_{6}\implies (\operatorname {equate} \land V=A_{6}))\land D=D}
( S 7 ( equate [ A 7 , q ] V [ F 7 ] = A 7 ) ) D [ F 7 ] = D [ q ] {\displaystyle \land (S_{7}\implies (\operatorname {equate} \land V=A_{7}))\land D=D}

After collecting the results together,

D [ p ] = [ q , _ , _ ] :: [ x , _ , _ ] :: L 3 {\displaystyle D=::::L_{3}}
D [ p ] = [ F 4 , S 4 , A 4 ] :: [ F 3 , S 3 , A 3 ] :: K 2 {\displaystyle D=::::K_{2}}
( S 3 ( equate [ A 3 , f ] V [ F 3 ] = A 3 ) ) D [ F 3 ] = D [ f ] {\displaystyle \land (S_{3}\implies (\operatorname {equate} \land V=A_{3}))\land D=D}
( S 4 ( equate [ A 4 , p ] V [ F 4 ] = A 4 ) ) D [ F 4 ] = D [ p ] {\displaystyle \land (S_{4}\implies (\operatorname {equate} \land V=A_{4}))\land D=D}
D [ q ] = [ F 7 , S 7 , A 7 ] :: [ F 6 , S 6 , A 6 ] :: K 5 {\displaystyle D=::::K_{5}}
( S 6 ( equate [ A 6 , x ] V [ F 6 ] = A 6 ) ) D [ F 6 ] = D [ x ] {\displaystyle (S_{6}\implies (\operatorname {equate} \land V=A_{6}))\land D=D}
( S 7 ( equate [ A 7 , q ] V [ F 7 ] = A 7 ) ) D [ F 7 ] = D [ q ] {\displaystyle (S_{7}\implies (\operatorname {equate} \land V=A_{7}))\land D=D}

From the two definitions for D [ p ] {\displaystyle D} ;

F 4 = q {\displaystyle F_{4}=q}
F 3 = x {\displaystyle F_{3}=x}

so

D [ p ] = [ q , S 4 , A 4 ] :: [ x , S 3 , A 3 ] :: K 2 {\displaystyle D=::::K_{2}}
( S 3 ( equate [ A 3 , f ] V [ x ] = A 3 ) ) D [ x ] = D [ f ] {\displaystyle (S_{3}\implies (\operatorname {equate} \land V=A_{3}))\land D=D}
( S 4 ( equate [ A 4 , p ] V [ q ] = A 4 ) ) D [ q ] = D [ p ] {\displaystyle (S_{4}\implies (\operatorname {equate} \land V=A_{4}))\land D=D}

Using D [ q ] = D [ p ] {\displaystyle D=D} and

D [ p ] = [ F 7 , S 7 , A 7 ] :: [ F 6 , S 6 , A 6 ] :: K 5 {\displaystyle D=::::K_{5}}
( S 6 ( equate [ A 6 , x ] V [ F 6 ] = A 6 ) ) D [ F 6 ] = D [ x ] {\displaystyle (S_{6}\implies (\operatorname {equate} \land V=A_{6}))\land D=D}
( S 7 ( equate [ A 7 , q ] V [ F 7 ] = A 7 ) ) D [ F 7 ] = D [ q ] {\displaystyle (S_{7}\implies (\operatorname {equate} \land V=A_{7}))\land D=D}

by comparing with the above,

F 7 = q , F 6 = x , A 3 = A 6 , A 4 = A 7 , S 3 = S 6 , S 4 = S 7 {\displaystyle F_{7}=q,F_{6}=x,A_{3}=A_{6},A_{4}=A_{7},S_{3}=S_{6},S_{4}=S_{7}}

so,

V [ x ] = A 3 {\displaystyle V=A_{3}}
V [ q ] = A 4 {\displaystyle V=A_{4}}

in,

S 3 A 3 = f {\displaystyle S_{3}\implies A_{3}=f}
S 3 ( A 3 = x A 3 = v [ x ] ) {\displaystyle S_{3}\implies (A_{3}=x\lor A_{3}=v)}

reduces to,

S 3 A 3 = f {\displaystyle S_{3}\implies A_{3}=f}

also,

S 4 A 4 = p {\displaystyle S_{4}\implies A_{4}=p}
S 4 ( A 4 = q A 4 = v [ q ] ) {\displaystyle S_{4}\implies (A_{4}=q\lor A_{4}=v)}

reduces to,

S 4 A 4 = p {\displaystyle S_{4}\implies A_{4}=p}

So the parameter list for p is effectively;

D [ p ] = [ q , _ , p ] :: [ x , _ , f ] :: _ {\displaystyle D=::::\_}

Drop parameters

Use the information obtained by Build parameter lists to drop actual parameters that are no longer required. drop-params has the parameters,

  • The lambda expression in which the parameters are to be dropped.
  • The mapping of variable names to parameter lists (built in Build parameter lists).
  • The set of variables free in the lambda expression.
  • The returned parameter list. A parameter used internally in the algorithm.

Abstraction

d r o p - p a r a m s [ ( λ N . S )   L , D , V , R ] ( λ N . d r o p - p a r a m s [ S , D , F , R ] )   d r o p - f o r m a l [ D [ N ] , L , F ] {\displaystyle \operatorname {drop-params} \equiv (\lambda N.\operatorname {drop-params} )\ \operatorname {drop-formal} ,L,F]}

where,

F = F V [ ( λ N . S )   L ] {\displaystyle F=FV}
d r o p - p a r a m s [ λ N . S , D , V , R ] ( λ N . d r o p - p a r a m s [ S , D , F , R ] ) {\displaystyle \operatorname {drop-params} \equiv (\lambda N.\operatorname {drop-params} )}

where,

F = F V [ λ N . S ] {\displaystyle F=FV}

Variable

d r o p - p a r a m s [ N , D , V , D [ N ] ] N {\displaystyle \operatorname {drop-params} ]\equiv N}

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

( def [ F ] ask [ S ] F V [ A ] V ) d r o p - p a r a m s [ E   P , D , V , R ] d r o p - p a r a m s [ E , D , V , [ F , S , A ] :: R ] {\displaystyle (\operatorname {def} \land \operatorname {ask} \land FV\subset V)\to \operatorname {drop-params} \equiv \operatorname {drop-params} ::R]}
¬ ( def [ F ] ask [ S ] F V [ A ] V ) d r o p - p a r a m s [ E   P , D , V , R ] d r o p - p a r a m s [ E , D , V , [ F , S , A ] :: R ]   d r o p - p a r a m s [ P , D , V , _ ] {\displaystyle \neg (\operatorname {def} \land \operatorname {ask} \land FV\subset V)\to \operatorname {drop-params} \equiv \operatorname {drop-params} ::R]\ \operatorname {drop-params} }

Let - Let expression.

d r o p - p a r a m s [ let V : E in L ] let V : d r o p - p a r a m s [ E , D , F V [ E ] , [ ] ] in d r o p - p a r a m s [ L , D , F V [ L ] , [ ] ] {\displaystyle \operatorname {drop-params} \equiv \operatorname {let} V:\operatorname {drop-params} ,]\operatorname {in} \operatorname {drop-params} ,]}

And - For use in "let".

d r o p - p a r a m s [ E F , D , V , _ ] d r o p - p a r a m s [ E , D , V , _ ] d r o p - p a r a m s [ F , D , V , _ ] {\displaystyle \operatorname {drop-params} \equiv \operatorname {drop-params} \land \operatorname {drop-params} }
Drop parameters from applications
λ g . λ n . n   ( g   m   p   n )   ( g   q   p   n ) {\displaystyle \lambda g.\lambda n.n\ (g\ m\ p\ n)\ (g\ q\ p\ n)}
Condition Expression
d r o p - p a r a m [ λ g . λ n . n   ( g   m   p   n )   ( g   q   p   n ) , D , { p , q , m } , _ ] {\displaystyle \operatorname {drop-param} }
λ g . d r o p - p a r a m [ λ n . n   ( g   m   p   n )   ( g   q   p   n ) , D , { p , q , m } , _ ] {\displaystyle \lambda g.\operatorname {drop-param} }
¬ ( def [ F 1 ] . . . ) {\displaystyle \neg (\operatorname {def} \land ...)} λ g . λ n . d r o p - p a r a m [ n   ( g   m   p   n ) , D , { p , q , m } , [ F 1 , S 1 , A 1 ] :: _ ]   d r o p - p a r a m [ ( g   q   p   n ) , D , { p , q , m } , _ ] {\displaystyle \lambda g.\lambda n.\operatorname {drop-param} ::\_]\ \operatorname {drop-param} }
¬ ( def [ F 2 ] . . . ) {\displaystyle \neg (\operatorname {def} \land ...)} λ g . λ n . d r o p - p a r a m [ n   , D , { p , q , m } , [ F 2 , S 2 , A 2 ] :: [ F 1 , S 1 , A 1 ] :: _ ]   d r o p - p a r a m [ ( g   m   p   n ) , D , { p , q , m } , _ ]   d r o p - p a r a m [ ( g   q   p   n ) , D , { p , q , m } , _ ] {\displaystyle \lambda g.\lambda n.\operatorname {drop-param} ::::\_]\ \operatorname {drop-param} \ \operatorname {drop-param} }
D [ n ] = [ F 2 , S 2 , A 2 ] :: [ F 1 , S 1 , A 1 ] :: _ ] {\displaystyle D=::::\_]} λ g . λ n . n   d r o p - p a r a m [ ( g   m   p   n ) , D , { p , q , m } , _ ]   d r o p - p a r a m [ ( g   q   p   n ) , D , { p , q , m } , _ ] {\displaystyle \lambda g.\lambda n.n\ \operatorname {drop-param} \ \operatorname {drop-param} }

From the results of building parameter lists;

D [ n ] = [ [ _ , _ , ( g   m   p   n ) ] , [ _ , _ , ( g   q   p   n ) ] ] {\displaystyle D=,]}

so,

F 1 = _ {\displaystyle F_{1}=\_}
F 2 = _ {\displaystyle F_{2}=\_}

so,

def [ F 1 ] = false {\displaystyle \operatorname {def} =\operatorname {false} }
def [ F 2 ] = false {\displaystyle \operatorname {def} =\operatorname {false} }
d r o p - p a r a m [ ( g   m   p   n ) , D , { p , q , m } , _ ] {\displaystyle \operatorname {drop-param} }
Condition Expanded Expression
V = { p , q , m } {\displaystyle V=\{p,q,m\}} d r o p - p a r a m [ ( g   m   p   n ) , D , V , _ ] {\displaystyle \operatorname {drop-param} }
F V ( A 1 ) { p , q , m } {\displaystyle FV(A_{1})\not \subset \{p,q,m\}} n { p , q , m } {\displaystyle n\not \subset \{p,q,m\}} d r o p - p a r a m s [ g   m   p , D , V , [ F 1 , S 1 , A 1 ] :: _ ]   d r o p - p a r a m s [ n , D , V , _ ] {\displaystyle \operatorname {drop-params} ::\_]\ \operatorname {drop-params} }
def [ F 2 ] ask [ S 2 ] F V [ A 2 ] V {\displaystyle \operatorname {def} \land \operatorname {ask} \land FV\subset V} def [ y ] ask [ _ ] F V [ p ] { p , q , m } {\displaystyle \operatorname {def} \land \operatorname {ask} \land FV\subset \{p,q,m\}} d r o p - p a r a m s [ g   m , D , V , [ F 2 , S 2 , A 2 ] :: [ F 1 , S 1 , A 1 ] :: _ ]   d r o p - p a r a m s [ n , D , V , _ ] {\displaystyle \operatorname {drop-params} ::::\_]\ \operatorname {drop-params} }
¬ ask [ S 3 ] {\displaystyle \neg \operatorname {ask} } ¬ ask [ false ] {\displaystyle \neg \operatorname {ask} } d r o p - p a r a m s [ g , D , V , [ F 3 , S 3 , A 3 ] :: [ F 2 , S 2 , A 2 ] :: [ F 1 , S 1 , A 1 ] :: _ ]   d r o p - p a r a m s [ m , D , V , _ ]   d r o p - p a r a m s [ n , D , V , _ ] {\displaystyle \operatorname {drop-params} ::::::\_]\ \operatorname {drop-params} \ \operatorname {drop-params} }

D [ g ] = [ [ x , false , _ ] , [ o , _ , p ] , [ y , _ , n ] ] {\displaystyle D=,,]} = [ F 3 , S 3 , A 3 ] :: [ F 2 , S 2 , A 2 ] :: [ F 1 , S 1 , A 1 ] :: _ ] {\displaystyle =::::::\_]}

F 3 = x , S 3 = false , A 3 = _ {\displaystyle F_{3}=x,S_{3}=\operatorname {false} ,A_{3}=\_} F 2 = o , S 2 = _ , A 2 = p {\displaystyle F_{2}=o,S_{2}=\_,A_{2}=p} F 1 = y , S 1 = _ , A 1 = n {\displaystyle F_{1}=y,S_{1}=\_,A_{1}=n}

g   m   n {\displaystyle g\ m\ n}

d r o p - p a r a m [ ( g   q   p   n ) , D , { p , q , m } , _ ] {\displaystyle \operatorname {drop-param} }
Condition Expanded Expression
V = \{p, q, m\} d r o p - p a r a m [ ( g   q   p   n ) , D , V , _ ] {\displaystyle \operatorname {drop-param} }
F V ( A 4 ) V {\displaystyle FV(A_{4})\not \subset V} n { p , q , m } {\displaystyle n\not \subset \{p,q,m\}} d r o p - p a r a m s [ g   q   p , D , V , [ F 4 , S 4 , A 4 ] :: _ ]   d r o p - p a r a m s [ n , D , V , _ ] {\displaystyle \operatorname {drop-params} ::\_]\ \operatorname {drop-params} }
def [ F 5 ] ask [ S 5 ] F V [ A 5 ] V {\displaystyle \operatorname {def} \land \operatorname {ask} \land FV\subset V} def [ o ] ask [ _ ] p { p , q , m } ) {\displaystyle \operatorname {def} \land \operatorname {ask} \land p\subset \{p,q,m\})} d r o p - p a r a m s [ g   q , D , V , [ F 5 , S 5 , A 5 ] :: [ F 4 , S 4 , A 4 ] :: _ ]   d r o p - p a r a m s [ n , D , V , _ ] {\displaystyle \operatorname {drop-params} ::::\_]\ \operatorname {drop-params} }
¬ ask [ S 6 ] {\displaystyle \neg \operatorname {ask} } ¬ ask [ false ] {\displaystyle \neg \operatorname {ask} } d r o p - p a r a m s [ g , D , V , [ F 6 , S 6 , A 6 ] :: [ F 5 , S 5 , A 5 ] :: [ F 4 , S 4 , A 4 ] :: _ ]   d r o p - p a r a m s [ m , D , V , _ ]   d r o p - p a r a m s [ n , D , V , _ ] {\displaystyle \operatorname {drop-params} ::::::\_]\ \operatorname {drop-params} \ \operatorname {drop-params} }

D [ g ] = [ [ x , false , _ ] , [ o , _ , p ] , [ y , _ , n ] ] {\displaystyle D=,,]} = [ F 6 , S 6 , A 6 ] :: [ F 5 , S 5 , A 5 ] :: [ F 4 , S 4 , A 4 ] :: _ ] {\displaystyle =::::::\_]}

F 6 = x , S 6 = false , A 6 = _ {\displaystyle F_{6}=x,S_{6}=\operatorname {false} ,A_{6}=\_} F 5 = o , S 5 = _ , A 5 = p {\displaystyle F_{5}=o,S_{5}=\_,A_{5}=p} F 4 = y , S 4 = _ , A 4 = n {\displaystyle F_{4}=y,S_{4}=\_,A_{4}=n}

g   q   n {\displaystyle g\ q\ n}

Drop formal parameters

drop-formal removes formal parameters, based on the contents of the drop lists. Its parameters are,

  • The drop list,
  • The function definition (lambda abstraction).
  • The free variables from the function definition.

drop-formal is defined as,

  1. ( ask [ S ] F V [ A ] V ) d r o p - f o r m a l [ [ F , S , A ] :: Z , λ F . Y , V ] d r o p - f o r m a l [ [ F , S , A ] :: Z , Y [ F := A ] , L ] {\displaystyle (\operatorname {ask} \land FV\subset V)\to \operatorname {drop-formal} ::Z,\lambda F.Y,V]\equiv \operatorname {drop-formal} ::Z,Y,L]}
  2. ¬ ( ask [ S ] F V [ A ] V ) d r o p - f o r m a l [ [ F , S , A ] :: Z , λ F . Y , V ] λ F . d r o p - f o r m a l [ [ F , S , A ] :: Z , Y , V ] {\displaystyle \neg (\operatorname {ask} \land FV\subset V)\to \operatorname {drop-formal} ::Z,\lambda F.Y,V]\equiv \lambda F.\operatorname {drop-formal} ::Z,Y,V]}
  3. d r o p - f o r m a l [ Z , Y , V ] Y {\displaystyle \operatorname {drop-formal} \equiv Y}

Which can be explained as,

  1. 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 its value.
  2. else do not drop the parameter.
  3. else return the body of the function.
Condition Expression
false {\displaystyle \operatorname {false} } d r o p - f o r m a l [ D , λ x . λ o . λ y . o   x   y , F ] {\displaystyle \operatorname {drop-formal} }
true { p } F {\displaystyle \operatorname {true} \land \{p\}\subset F} λ x . d r o p - f o r m a l [ D , λ o . λ y . o   x   y , F ] {\displaystyle \lambda x.\operatorname {drop-formal} }
¬ ( true { n } F {\displaystyle \neg (\operatorname {true} \land \{n\}\subset F} ) λ x . d r o p - f o r m a l [ D , ( λ y . o   x   y ) [ o := p ] , F ] {\displaystyle \lambda x.\operatorname {drop-formal} ,F]}
λ x . λ y . d r o p - f o r m a l [ D , p   x   y , F ] {\displaystyle \lambda x.\lambda y.\operatorname {drop-formal} }
λ x . λ y . p   x   y {\displaystyle \lambda x.\lambda y.p\ x\ y}

Example

Starting with the function definition of the Y-combinator,

let p   f   x = f   ( x   x ) q   p   f = ( p   f )   ( p   f ) in q   p   {\displaystyle \operatorname {let} p\ f\ x=f\ (x\ x)\land q\ p\ f=(p\ f)\ (p\ f)\operatorname {in} q\ p\ }
Transformation Expression
let p   f   x = f   ( x   x ) q   p   f = ( p   f )   ( p   f ) in q   p {\displaystyle \operatorname {let} p\ f\ x=f\ (x\ x)\land q\ p\ f=(p\ f)\ (p\ f)\operatorname {in} q\ p}
abstract * 4 let p = λ f . λ x . f   ( x   x ) q = λ p . λ f . ( p   f )   ( p   f ) in q   p {\displaystyle \operatorname {let} p=\lambda f.\lambda x.f\ (x\ x)\land q=\lambda p.\lambda f.(p\ f)\ (p\ f)\operatorname {in} q\ p}
lambda-abstract-tran ( λ q . ( λ p . q   p )   ( λ f . λ x . f   ( x   x ) ) )   ( λ p . λ f . ( p   f )   ( p   f ) ) {\displaystyle (\lambda q.(\lambda p.q\ p)\ (\lambda f.\lambda x.f\ (x\ x)))\ (\lambda p.\lambda f.(p\ f)\ (p\ f))}
sink-tran ( λ p . λ f . ( p   f )   ( p   f ) )   ( λ f . λ x . f   ( x   x ) ) {\displaystyle (\lambda p.\lambda f.(p\ f)\ (p\ f))\ (\lambda f.\lambda x.f\ (x\ x))}
sink-tran λ f . ( λ p . ( p   f )   ( p   f ) )   ( λ f . λ x . f   ( x   x ) ) {\displaystyle \lambda f.(\lambda p.(p\ f)\ (p\ f))\ (\lambda f.\lambda x.f\ (x\ x))}
drop-param λ f . ( λ p . p   p )   ( λ x . f   ( x   x ) ) {\displaystyle \lambda f.(\lambda p.p\ p)\ (\lambda x.f\ (x\ x))}
beta-redex λ f . ( λ x . f   ( x   x ) )   ( λ x . f   ( x   x ) )   {\displaystyle \lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x))\ }

Which gives back the Y combinator,

λ f . ( λ x . f   ( x   x ) )   ( λ x . f   ( x   x ) ) {\displaystyle \lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x))}

See also

References

  1. Johnsson, Thomas (1985). "Lambda Lifting: Transforming Programs to Recursive Equations". In Jouannaud, J.P. (ed.). Functional Programming Languages and Computer Architecture. FPCA 1985. Lecture Notes in Computer Science. Vol. 201. Springer. CiteSeerX 10.1.1.48.4346. doi:10.1007/3-540-15975-4_37. ISBN 3-540-15975-4.
  2. Morazán, Marco T.; Schultz, Ulrik P. (2008), "Optimal Lambda Lifting in Quadratic Time", Implementation and Application of Functional Languages — Revised Selected Papers, pp. 37–56, doi:10.1007/978-3-540-85373-2_3, ISBN 978-3-540-85372-5
  3. Danvy, O.; Schultz, U. P. (1997). "Lambda-dropping". ACM SIGPLAN Notices. 32 (12): 90. doi:10.1145/258994.259007.
  4. Danvy, Olivier; Schultz, Ulrik P. (October 2000). "Lambda-Dropping: Transforming Recursive Equations into Programs with Block Structure" (PDF). Theoretical Computer Science. 248 (1–2): 243–287. CiteSeerX 10.1.1.16.3943. doi:10.1016/S0304-3975(00)00054-2. BRICS-RS-99-27.

External links

Categories: