{"id":1659,"date":"2012-01-18T20:29:36","date_gmt":"2012-01-19T01:29:36","guid":{"rendered":"http:\/\/scientopia.org\/blogs\/goodmath\/?p=1659"},"modified":"2012-01-18T20:29:36","modified_gmt":"2012-01-19T01:29:36","slug":"sidetrack-from-the-cccs-lambda-calculus","status":"publish","type":"post","link":"http:\/\/www.goodmath.org\/blog\/2012\/01\/18\/sidetrack-from-the-cccs-lambda-calculus\/","title":{"rendered":"Sidetrack from the CCCs: Lambda Calculus"},"content":{"rendered":"<p> So, last post, I finally defined closed cartesian categories. And I alluded to the fact that the CCCs are, essentially, equivalent to the simply typed &lambda; calculus. But I didn&#8217;t really talk about what that meant.<\/p>\n<p> Before I can get to that, you need to know what &lambda; calculus is. Many readers are probably familiar, but others aren&#8217;t. And as it happens, I absolutely <em>love<\/em> &lambda; calculus.<\/p>\n<p> In computer science, especially in the field of programming languages, we tend to use &lambda; calculus a whole lot. It&#8217;s 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: if a function can be computed by any possible computing device, then it can be written in &lambda;-calculus.<\/li>\n<li>It&#8217;s easy to read and write.<\/li>\n<li> Its 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, Haskell, and my current favorite, Scala, are very strongly &lambda; calculus based.<\/p>\n<p> The &lambda; calculus is based on the concept of <em>functions<\/em>. In the pure &lambda; calculus, <em>everything<\/em> is a function; there are no values except for functions. In fact, we can pretty much build up all of mathematics using &lambda;-calculus.<\/p>\n<p> With the lead-in out of the way, let&#8217;s dive in a look at &lambda;-calculus. To define 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:  <em>&lambda; param . body<\/em>, 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 <em>x y<\/em> to apply the function <em>x<\/em> to the value <em>y<\/em>.<\/li>\n<\/ol>\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, themselves, values. Instead of writing a two parameter function, you can write a one parameter function that returns a one parameter function, which can then operate on the second parameter. In the end, it&#8217;s effectively the same thing as a two parameter function. Taking a two-parameter function, and representing it by two one-parameter functions is 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: <em>&lambda; x y . x + y<\/em>. 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: <em>&lambda; x . (&lambda; y . x + y)<\/em>. <\/p>\n<p> Now that we know that adding multiple parameter functions doesn&#8217;t <em>really<\/em> add anything but a bit of simplified syntax, we&#8217;ll go ahead and use them when it&#8217;s convenient.<\/p>\n<p> One important syntactic issue that I haven&#8217;t mentioned yet is <em>closure<\/em> or <em>complete binding<\/em>. For a &lambda; calculus expression to be evaluated, it cannot reference any identifiers that are not <em>bound<\/em>. An identifier is bound if it a parameter in an enclosing &lambda; expression; if an identifier is <em>not<\/em> bound in any enclosing context, then it is called a <em>free<\/em> variable. Let&#8217;s look quickly at a few examples:<\/p>\n<ul>\n<li> <em>&lambda; x . p x y<\/em>: in this expression, <em>y<\/em> and <em>p<\/em> 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 <em>p x y<\/em> where it&#8217;s referenced.<\/li>\n<li> <em>&lambda; x y.y x<\/em>: in this expression both x and y are bound, because they are parameters of the function definition, and there are no free variables.<\/li>\n<li> <em>&lambda; y . (&lambda; x . p x y)<\/em>. This one is a tad more complicated, because we&#8217;ve got the inner &lambda;. So let&#8217;s start there. In the inner &lambda;, <em>&lambda; x . p x y<\/em>, y and p 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;p&#8221; is still free.<\/li>\n<\/ul>\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 valid (and thus evaluatable) 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.<\/p>\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<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><center><br \/>\n&lambda; x . if (= x 0) then 1 else x^2<br \/>\n<\/center><\/p>\n<p> We can do an &alpha; to replace X with Y (written &#8220;&alpha;[x\/y]&#8221; and get):<\/p>\n<p><center><br \/>\n&lambda; y . if (= y 0) then 1 else y^2<br \/>\n<\/center><\/p>\n<p> Doing &alpha; does <em>not<\/em> change the <em>meaning<\/em> of the expression in any way. But as we&#8217;ll see later, it&#8217;s important because without it, we&#8217;d often wind up with situations where a single variable symbol is bound by two different enclosing &lambda;s. This will be particularly important when we get to recursion.<\/p>\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 <em>any<\/em> 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: <em>(&lambda; x . x + 1) 3<\/em>. By performing a beta reduction, we can replace the application by taking the body <em>x + 1<\/em> of the function, and substituting (or &alpha;ing) the value of the parameter (3) for the parameter variable symbol (x). So we replace all references to <em>x<\/em> with <em>3<\/em>. So the result of doing a beta reduction xs <em>3 + 1<\/em>.<\/p>\n<p> A slightly more complicated example is the expression:<\/p>\n<pre>\n&lambda; y . (&lambda; x . x + y)) q\n<\/pre>\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 <em>y<\/em> with the identifier <em>q<\/em>; so, the result is <em>&lambda; x . x + q<\/em>.<\/p>\n<p> One more example, just for the sake of being annoying. Suppose we have: <em>(&lambda; x y. x y) (&lambda; z . z * z) 3<\/em><\/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 <em>x<\/em> in the body of the first function with <em>&lambda; z . z * z<\/em>; and we replace the parameter <em>y<\/em> with <em>3<\/em>, getting: <em>(&lambda; z . z * z) 3<\/em>. And we can perform beta on that, getting <em>3 * 3<\/em>.<\/p>\n<p> Written formally, beta says: <em>&lambda; x . B e = B[x := e] if free(e) &sub; free(B[x := e])<\/em><\/p>\n<p> That condition on the end, &#8220;if free(e) &sub; free(B[x := e]&#8221; is why we need &alpha;: we can only do beta reduction <em>if<\/em> 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 \u03b1 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, <em>&lambda; z . (&lambda; x . x+z)<\/em>. Now, suppose we want to apply it: <em>(&lambda; z . (&lambda; x . x + z)) (x + 2)<\/em>. In the parameter <em>(x + 2)<\/em>, <em>x<\/em> is free. Now, suppose we break the rule and go ahead and do beta. We&#8217;d get &#8220;<em>&lambda; x . x + x + 2<\/em>&#8220;. The variable that <em>was<\/em> free in <em>x + 2<\/em> is now bound! We&#8217;ve changed the meaning of the function, which we shouldn&#8217;t be able to do. If we were to apply that function after the incorrect &beta;, we&#8217;d get <em>(&lambda; x . x + x + 2) 3<\/em>. By beta, we&#8217;d get <em>3 + 3 + 2<\/em>, or 8.<\/p>\n<p> What if we did &alpha; the way we were supposed to?<\/p>\n<p> First, we&#8217;d do an &alpha; to prevent the name overlap. By &alpha;[x\/y], we would get <em>&lambda; z . (&lambda; y . y + z) (x+2)<\/em>.<\/p>\n<p> Then by &beta;, we&#8217;d get &#8220;<em>&lambda; y . y + x + 2<\/em>&#8220;. If we apply this function the way we did above, then by &beta;, we&#8217;d get <em>3+x+2<\/em>.<br \/>\n<em>3+x+2<\/em> and <em>3+3+2<\/em> are very different results!<\/p>\n<p> And that&#8217;s pretty much it. There&#8217;s another <em>optional<\/em> rule you can add called &eta;-conversion. &eta; is a rule that adds <em>extensionality<\/em>, which provides a way of expressing equality between functions.<\/p>\n<p> &eta; says that in any &lambda; expression, I can replace the value <em>f<\/em> with the value <em>g<\/em> if\/f for all possible parameter values x, <em>f x = g x<\/em>.<\/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> It&#8217;l also important to point out that while I&#8217;ve gone through a basic definition of &lambda; calculus, and described its mechanics, I haven&#8217;t yet defined a <em>model<\/em> for &lambda;-calculus. That&#8217;s quite an important omission! &lambda;-calculus 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 it looked correct, the early attempts to define a model for it were failures! And without a valid model, the results of the system are <em>meaningless<\/em>. An invalid model in a logical system like calculus is like a contradiction in axioms: it means that nothing that it produces is valid. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>So, last post, I finally defined closed cartesian categories. And I alluded to the fact that the CCCs are, essentially, equivalent to the simply typed &lambda; calculus. But I didn&#8217;t really talk about what that meant. Before I can get to that, you need to know what &lambda; calculus is. Many readers are probably familiar, [&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":[76,32],"tags":[117,307,193],"class_list":["post-1659","post","type-post","status-publish","format-standard","hentry","category-category-theory","category-lambda-calculus","tag-calculus","tag-lambda-calculus","tag-logic-2"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p4lzZS-qL","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/1659","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=1659"}],"version-history":[{"count":0,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/1659\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/media?parent=1659"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/categories?post=1659"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/tags?post=1659"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}