A
lambda abstraction represents a function without a name. This is a
source of the inconsistency in the definition of a lambda abstraction. However lambda abstractions may be composed to represent a function with a name. In this form the inconsistency is removed. The lambda term, : (\lambda f.z)\ (\lambda x.y) is equivalent to defining the function f by f\ x = y in the expression z, which may be written as the
let expression; :\operatorname{let} f\ x = y \operatorname{in} z The let expression is understandable as a natural language expression. The let expression represents the substitution of a variable for a value. The substitution rule describes the implications of equality as substitution.
Let definition in mathematics In
mathematics the
let expression is described as the conjunction of expressions. In functional languages the let expression is also used to limit scope. In mathematics scope is described by quantifiers. The let expression is a conjunction within an existential quantifier. : (\exists x E \land F) \iff \operatorname{let} x : E \operatorname{in} F where
E and
F are of type Boolean. The
let expression allows the substitution to be applied to another expression. This substitution may be applied within a restricted scope, to a sub expression. The natural use of the let expression is in application to a restricted scope (called
lambda dropping). These rules define how the scope may be restricted; :\begin{cases} x \not \in \operatorname{FV}(E) \land x \in \operatorname{FV}(F) \implies \operatorname{let} x : G \operatorname{in} E\ F = E\ (\operatorname{let} x : G \operatorname{in} F)\\ x \in \operatorname{FV}(E) \land x \not \in \operatorname{FV}(F) \implies \operatorname{let} x : G \operatorname{in} E\ F = (\operatorname{let} x : G \operatorname{in} E)\ F\\ x \not \in \operatorname{FV}(E) \land x \not \in \operatorname{FV}(F) \implies \operatorname{let} x : G \operatorname{in} E\ F = E\ F \end{cases} where
F is
not of type Boolean. From this definition the following standard definition of a let expression, as used in a functional language may be derived. : x \not \in \operatorname{FV}(y) \implies (\operatorname{let} x : x = y \operatorname{in} z) = z[x := y] = (\lambda x.z)\ y For simplicity the marker specifying the existential variable, x :, will be omitted from the expression where it is clear from the context. : x \not \in \operatorname{FV}(y) \implies (\operatorname{let} x = y \operatorname{in} z) = z[x := y] = (\lambda x.z)\ y
Derivation To derive this result, first assume, : x \not \in \operatorname{FV}(L) then :\begin{align} L\ (\operatorname{let} x : x = y \operatorname{in} z) & \iff (\operatorname{let} x : x = y \operatorname{in} L\ z) \\ & \iff x = y \land L\ z \end{align} Using the rule of substitution, :\begin{align} & \iff x = y \land(L\ z)[x :=y]\\ & \iff x = y \land(L[x :=y]\ z[x :=y])\\ & \iff x = y \land L\ z[x :=y]\\ & \implies L\ z[x :=y] \end{align} so for all
L, : L \operatorname{let} x : x = y \operatorname{in} z \implies L\ z[x :=y] Let L\ X = (X = K) where
K is a new variable. then, : (\operatorname{let} x : x = y \operatorname{in} z) = K \implies z[x :=y] = K So, : \operatorname{let} x : x = y \operatorname{in} z = z[x :=y] But from the mathematical interpretation of a beta reduction, : (\lambda x.z)\ y = z[x :=y] Here if y is a function of a variable x, it is not the same x as in z. Alpha renaming may be applied. So we must have, : x \not \in \operatorname{FV}(y) so, : x \not \in \operatorname{FV}(y) \implies \operatorname{let} x : x = y \operatorname{in} z = (\lambda x.z)\ y This result is represented in a functional language in an abbreviated form, where the meaning is unambiguous; : x \not \in \operatorname{FV}(y) \implies (\operatorname{let} x = y \operatorname{in} z) = z[x := y] = (\lambda x.z)\ y Here the variable
x is implicitly recognised as both part of the equation defining x, and the variable in the existential quantifier.
No lifting from Boolean A contradiction arises if E is defined by E = \neg . In this case, : x \not \in \operatorname{FV}(E) \land x \in \operatorname{FV}(F) \implies \operatorname{let} x : G \operatorname{in} E\ F = E\ (\operatorname{let} x : G \operatorname{in} F) becomes, : \operatorname{let} x : G \operatorname{in} \neg F = \neg\ (\operatorname{let} x : G \operatorname{in} F) and using, : (\exists x E \land F) \iff \operatorname{let} x : E \operatorname{in} F : (\exists x G \land \neg F) = \neg\ (\exists x G \land F) : = (\exists x \neg G \lor \neg F) This is false if G is false. To avoid this contradiction
F is not allowed to be of type Boolean. For Boolean
F the correct statement of the dropping rule uses implication instead of equality, : x \not \in \operatorname{FV}(E) \land x \in \operatorname{FV}(F) \implies (\operatorname{let} x : G \operatorname{in} E\ F \to E\ (\operatorname{let} x : G \operatorname{in} F)) It may appear strange that a different rule applies for Boolean than other types. The reason for this is that the rule, : (\exists x E \land F) \iff \operatorname{let} x : E \operatorname{in} F only applies where
F is Boolean. The combination of the two rules creates a contradiction, so where one rule holds, the other does not.
Joining let expressions Let expressions may be defined with multiple variables, : (\exists v \cdots \exists w \exists x E \land F) \iff \operatorname{let} v, \ldots ,w , x : E \operatorname{in} F then it can be derived, : x \not \in FV(E) \implies (\exists v \cdots \exists w \exists x E \land F) \iff (\exists v \cdots \exists w (E \land \exists x F)) so, : x \not \in FV(E) \implies (\operatorname{let} v, \ldots, w, x : E \land F \operatorname{in} L \equiv \operatorname{let} v, \ldots, w: E \operatorname{in} \operatorname{let} x : F \operatorname{in} L)
Laws relating lambda calculus and let expressions The
Eta reduction gives a rule for describing lambda abstractions. This rule along with the two laws derived above define the relationship between lambda calculus and let expressions.
Let definition defined from lambda calculus To avoid the
potential problems associated with the
mathematical definition,
Dana Scott originally defined the
let expression from lambda calculus. This may be considered as the bottom up, or constructive, definition of the
let expression, in contrast to the top down, or axiomatic mathematical definition. The simple, non recursive
let expression was defined as being
syntactic sugar for the lambda abstraction applied to a term. In that definition, :(\operatorname{let}_s x = y \operatorname{in} z) \equiv (\lambda x.z)\ y The simple
let expression definition was then extended to allow recursion using the
fixed-point combinator.
Fixed-point combinator The
fixed-point combinator may be represented by the expression, : \lambda f.\operatorname{let} x = f\ x \operatorname{in} x This representation may be converted into a lambda term. A lambda abstraction does not support reference to the variable name, in the applied expression, so
x must be passed in as a parameter to
x. : \lambda f.\operatorname{let} x\ x = f\ (x\ x) \operatorname{in} x\ x Using the eta reduction rule, : f\ x = y \equiv f = \lambda x.y gives, : \lambda f.\operatorname{let} x = \lambda x.f\ (x\ x) \operatorname{in} x\ x A let expression may be expressed as a lambda abstraction using, : n \not \in FV(E) \to (\operatorname{let} n = E \operatorname{in} L \equiv (\lambda n.L)\ E) gives, : \lambda f.(\lambda x.x\ x)\ (\lambda x.f\ (x\ x)) This is possibly the simplest implementation of a fixed point combinator in lambda calculus. However one beta reduction gives the more symmetrical form of Curry's Y combinator. : \lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x))
Recursive let expression The recursive
let expression called "let rec" is defined using the Y combinator for recursive let expressions. :(\operatorname{let\ rec} x = y \operatorname{in} z) \equiv (\lambda x.z)\ (Y\ (\lambda x.y))
Mutually recursive let expression This approach is then generalized to support mutual recursion. A mutually recursive let expression may be composed by rearranging the expression to remove any and conditions. This is achieved by replacing multiple function definitions with a single function definition, which sets a list of variables equal to a list of expressions. A version of the Y combinator, called the
Y* poly-variadic fix-point combinator is then used to calculate fixed point of all the functions at the same time. The result is a mutually recursive implementation of the
let expression. == Multiple values ==