{"id":135,"date":"2006-08-29T08:30:00","date_gmt":"2006-08-29T08:30:00","guid":{"rendered":"http:\/\/scientopia.org\/blogs\/goodmath\/2006\/08\/29\/a-lambda-calculus-rerun\/"},"modified":"2016-06-21T21:06:13","modified_gmt":"2016-06-22T01:06:13","slug":"a-lambda-calculus-rerun","status":"publish","type":"post","link":"http:\/\/www.goodmath.org\/blog\/2006\/08\/29\/a-lambda-calculus-rerun\/","title":{"rendered":"A Lambda Calculus rerun"},"content":{"rendered":"<p> I&#8217;m on vacation this week, so I&#8217;m recycling some posts that I thought were particularly interesting to give you something to read.<\/p>\n<p>In computer science, especially in the field of programming languages, we tend to use one particular calculus a lot: the Lambda calculus. Lambda calculus is also extensively used by logicians studying the nature of computation and the structure of discrete mathematics. Lambda calculus is great for a lot of reasons, among them:<\/p>\n<ol>\n<li> It&#8217;s very simple.<\/li>\n<li> It&#8217;s Turing complete.<\/li>\n<li> It&#8217;s easy to read and write.<\/li>\n<li> It&#8217;s semantics are strong enough that we can do reasoning from it.<\/li>\n<li> It&#8217;s got a good solid model.<\/li>\n<li> It&#8217;s easy to create variants to explore the properties of various alternative ways of structuring computations or semantics.<\/li>\n<\/ol>\n<p>The ease of reading and writing lambda calculus is a big deal. It&#8217;s led to the development of a lot of extremely good programming languages based, to one degree or another, on the lambda calculus: Lisp, ML, and Haskell are very strongly lambda calculus based.<\/p>\n<p>The lambda calculus is based on the concept of *functions*&gt;. In the pure lambda calculus, *everything* is a function; there are no values *at all* except for functions. But we can build up anything we need using functions. Remember back in the early days of this blog, I talked a bit about how to build mathematics? We can build the entire structure of mathematics from nothing but lambda calculus.<\/p>\n<p>So, enough lead-in. Let&#8217;s dive in a look at LC. Remember that for a calculus, you need to define two things: the syntax, which describes how valid expressions can be written in the calculus; and a set of rules that allow you to symbolically manipulate the expressions.<\/p>\n<h3>Lambda Calculus Syntax<\/h3>\n<p>The lambda calculus has exactly three kinds of expressions:<\/p>\n<ol>\n<li> Function definition: a function in lambda calculus is an expression, written: &#8220;<code>&lambda; param . body<\/code>&#8221; which defines a function with one parameter.<\/li>\n<li> Identifier reference: an identifier reference is a name which matches the name of a parameter defined in a function expression enclosing the reference.<\/li>\n<li> Function application: applying a function is written by putting the function value in front of its parameter, as in &#8220;<code>x y<\/code>&#8221; to apply the function <code>x<\/code> to the value <code>y<\/code>.<\/li>\n<\/ol>\n<h4>Currying<\/h4>\n<p>There&#8217;s a trick that we play in lambda calculus: if you look at the definition above, you&#8217;ll notice that a function (lambda expression) only takes one parameter. That seems like a very big constraint &#8211; how can you even implement addition with only one parameter?<\/p>\n<p>It turns out to be no problem, because of the fact that *functions are values*. So instead of writing a two parameter function, you can write a one parameter function that returns a one parameter function &#8211; in the end, it&#8217;s effectively the same thing. It&#8217;s called currying, after the great logician Haskell Curry.<\/p>\n<p>For example, suppose we wanted to write a function to add x and y. We&#8217;d like to write something like: <code>&lambda; x y .  x + y<\/code>.  The way we do that with one-parameter functions is: we first write a function with one parameter, which returns <em>another<\/em> function with one parameter.<\/p>\n<p> Adding x plus y becomes writing a one-parameter function with parameter x, which returns another one parameter function which adds x to its parameter:<\/p>\n<p><code>&lambda; x . (&lambda; y . x + y)<\/code><\/p>\n<p> Now that we know that adding multiple parameter functions doesn&#8217;t *really* add anything but a bit of simplified syntax, we&#8217;ll go ahead and use them when it&#8217;s convenient.<\/p>\n<h4>Free vs Bound Identifiers<\/h4>\n<p> One important syntactic issue that I haven&#8217;t mentioned yet is *closure* or *complete binding*. For a lambda calculus expression to be evaluated, it cannot reference any identifiers that are not *bound*. An identifier is bound if it a parameter in an enclosing lambda expression; if an identifier is *not* bound in any enclosing context, then it is called a *free* variable.<\/p>\n<ol>\n<li> *&lambda; x . plus x y*: in this expression, &#8220;y&#8221; and &#8220;plus&#8221; are free, because they&#8217;re not the parameter of any enclosing lambda expression; x is bound because it&#8217;s a parameter of the function definition enclosing the expression &#8220;plus x y&#8221; where it&#8217;s referenced.<\/li>\n<li> *&lambda; x y.y x*: in this expression both x and y are bound, because they are parameters of the function definition.<\/li>\n<li> *&lambda; y . (&lambda; x . plus x y*: In the inner lambda, &#8220;*&lambda; x . plus x y*&#8221;, y and plus are free and x is bound. In the full expression, both x and y are bound: x is bound by the inner lambda, and y is bound by the other lambda. &#8220;plus&#8221; is still free.<\/li>\n<\/ol>\n<p>We&#8217;ll often use &#8220;free(x)&#8221; to mean the set of identifiers that are free in the expression &#8220;x&#8221;.<\/p>\n<p>A lambda calculus expression is completely valid only when all of its variables are bound. But when we look at smaller subexpressions of a complex expression, taken out of context, they can have free variables &#8211; and making sure that the variables that are free in subexpressions are treated right is very important.<\/li>\n<h3>Lambda Calculus Evaluation Rules<\/h3>\n<p>There are only two real rules for evaluating expressions in lambda calculus; they&#8217;re called &alpha; and beta. &alpha; is also called &#8220;conversion&#8221;, and beta is also called &#8220;reduction&#8221;.<\/p>\n<h4>&alpha; Conversion<\/h4>\n<p>&alpha; is a renaming operation; basically it says that the names of variables are  unimportant: given any expression in lambda calculus, we can change the name of the parameter to a function as long as we change all free references to it inside the body.<\/p>\n<p>So &#8211; for instance, if we had an expression like:<\/p>\n<p><em>&lambda; x . if (= x  0) then 1 else x^2<\/em><\/p>\n<p> We can do &alpha; to replace X with Y (written &#8220;&alpha;[x\/y]&#8221; and get):<\/p>\n<p><em>&lambda; y . if (= y  0) then 1 else y^2<\/em><\/p>\n<p>Doing &alpha; does *not* change the meaning of the expression in any way. But as we&#8217;ll see later, it&#8217;s important because it gives us a way of doing things like recursion.<\/p>\n<h4>&beta; Reduction<\/h4>\n<p>&beta; reduction is where things get interesting: this single rule is all that&#8217;s needed to make the lambda calculus capable of performing *any* computation that can be done by a machine.<\/p>\n<p>Beta basically says that if you have a function application, you can replace it with a copy of the body of the function with references to the parameter identifiers replaced by references to the parameter value in the application. That sounds confusing, but it&#8217;s actually pretty easy when you see it in action.<\/p>\n<p>Suppose we have the application expression: &#8220;*(&lambda; x . x + 1) 3*<\/code>&#8220;. What beta says is that we can replace the application by taking the body of the function (which is &#8220;*x + 1*&#8221;); and replacing references to the parameter &#8220;*x*&#8221; by the value &#8220;*3*&#8221;; so the result of the beta reduction is &#8220;*3 + 1*&#8221;.<\/p>\n<p> A slightly more complicated example is the expression:<\/p>\n<p><em>&lambda; y . (&lambda; x . x + y)) q<\/em><\/p>\n<p>It&#8217;s an interesting expression, because it&#8217;s a lambda expression that when applied, results in another lambda expression: that is, it&#8217;s a function that creates functions. When we do beta reduction in this, we&#8217;re replacing all references to the parameter &#8220;y&#8221; with the identifier &#8220;q&#8221;; so, the result is &#8220;*&lambda; x. x+q*&#8221;.<\/p>\n<p>One more example, just for the sake of being annoying:<\/p>\n<p>&#8220;<em>(&lambda; x y. x y) (&lambda; z . z &times; z) 3<\/em>&#8220;.<\/p>\n<p> That&#8217;s a function that takes two parameters, and applies the first one to the second one. When we evaluate that, we replace the parameter &#8220;*x*&#8221; in the body of the first function with &#8220;*&lambda; z . z &times; z<\/code>*&#8221;; and we replace the parameter &#8220;*y*&#8221; with &#8220;3&#8221;, getting: &#8220;*(&lambda; z . z &times; z) 3*&#8221;. And we can perform beta on that, getting &#8220;*3 &times; 3*&#8221;.<\/p>\n<p>Written formally, beta says:<\/p>\n<p>&lambda; x . B e = B[x := e] if free(e) &sub; free(B[x := e]<\/p>\n<p>That condition on the end, &#8220;if free(e) subset free(B[x := e]&#8221; is why we need &alpha;: we can only do beta reduction *if* doing it doesn&#8217;t create any collisions between bound identifiers and free identifiers: if the identifier &#8220;z&#8221; is free in &#8220;e&#8221;, then we need to be sure that the beta-reduction doesn&#8217;t make &#8220;z&#8221; become bound. If there is a name collision between a variable that is bound in &#8220;B&#8221; and a variable that is free in &#8220;e&#8221;, then we need to use &alpha; to change the identifier names so that they&#8217;re different.<\/p>\n<p>As usual, an example will make that clearer: Suppose we have a expression defining a function, &#8220;*&lambda; z . (&lambda; x . x+z)*&#8221;. Now, suppose we want to apply it:<\/p>\n<p><em>(&lambda; z . (&lambda; x . x + z)) (x + 2)<\/em><\/p>\n<p>In the parameter &#8220;*(x + 2)*&#8221;, x is free. Now, suppose we break the rule and go ahead and do beta. We&#8217;d get &#8220;*&lambda; x . x + x + 2*&#8221;.<\/p>\n<p>The variable that was *free* in &#8220;x + 2&#8221; is now bound. Now suppose we apply that function: &#8220;*(&lambda; x . x + x + 2) 3*&#8221;. By beta, we&#8217;d get &#8220;3 + 3 + 2&#8221;, or 8.<\/p>\n<p> What if we did &alpha; the way we were supposed to?<\/p>\n<ul>\n<li> By &alpha;[x\/y], we would get &#8220;*&lambda; z . (&lambda; y . y + z) (x+2)*&#8221;.<\/li>\n<li> by &alpha;[x\/y]:  <code>lambda z . (lambda y . y+z)) (x + 2)<\/code>. Then by &beta;, we&#8217;d get &#8220;*&lambda; y . y + x + 2*&#8221;. If we apply this function the way we did above, then by &beta;, we&#8217;d get &#8220;*3+x+2*&#8221;.<\/li>\n<\/ul>\n<p>&#8220;*3+x+2*&#8221; and &#8220;*3+3+2*&#8221; are very different results!<\/p>\n<p>And that&#8217;s pretty much it. There&#8217;s another *optional* rule you can  add called &eta;-conversion. &eta; is a rule that adds *extensionality*, which provides a way of expressing equality between functions.<\/p>\n<p>&eta; says that in any lambda expression, I can replace the value &#8220;f&#8221; with the value &#8220;g&#8221; if\/f for all possible parameter values x, *f x = g x*.<\/p>\n<p>What I&#8217;ve described here is Turing complete &#8211; a full effective computation system. To make it useful, and see how this can be used to do real stuff, we need to define a bunch of basic functions that allow us to do math, condition tests, recursion, etc. I&#8217;ll talk about those in my next post.<\/p>\n<p> We also haven&#8217;t defined a model for lambda-calculus yet. (I discussed models <a href=\"http:\/\/goodmath.blogspot.com\/2006\/04\/more-logic-models-and-why-they-matter.html\">here<\/a> and <a href=\"http:\/\/goodmath.blogspot.com\/2006\/04\/correcting-my-models-post-or-why.html\">here<\/a>.)  That&#8217;s actually quite an important thing! LC was played with by logicians for several years before they were able to come up with a complete model for it, and it was a matter of great concern that although LC looked correct, the early attempts to define a model for it were failures. After all, remember that if there isn&#8217;t a valid model, that means that the results of the system are meaningless!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;m on vacation this week, so I&#8217;m recycling some posts that I thought were particularly interesting to give you something to read. In computer science, especially in the field of programming languages, we tend to use one particular calculus a lot: the Lambda calculus. Lambda calculus is also extensively used by logicians studying the nature [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[24,32],"tags":[],"class_list":["post-135","post","type-post","status-publish","format-standard","hentry","category-goodmath","category-lambda-calculus"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p4lzZS-2b","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/135","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/comments?post=135"}],"version-history":[{"count":2,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/135\/revisions"}],"predecessor-version":[{"id":3275,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/135\/revisions\/3275"}],"wp:attachment":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/media?parent=135"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/categories?post=135"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/tags?post=135"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}