{"id":111,"date":"2006-08-11T14:47:33","date_gmt":"2006-08-11T14:47:33","guid":{"rendered":"http:\/\/scientopia.org\/blogs\/goodmath\/2006\/08\/11\/friday-pathological-programming-unlambda-or-programming-without-variables\/"},"modified":"2006-08-11T14:47:33","modified_gmt":"2006-08-11T14:47:33","slug":"friday-pathological-programming-unlambda-or-programming-without-variables","status":"publish","type":"post","link":"http:\/\/www.goodmath.org\/blog\/2006\/08\/11\/friday-pathological-programming-unlambda-or-programming-without-variables\/","title":{"rendered":"Friday Pathological Programming: Unlambda, or Programming Without Variables"},"content":{"rendered":"<p>Todays tasty treat: a variable-free nearly-pure functional programming language: Unlambda.<br \/>\nUnlambda is based on the SKI combinator calculus. The [SKI calculus][ski] is a way of writing lambda calculus without variables, and without lambda. It&#8217;s based on three combinators: S, K, and I:<br \/>\n1. S = &lambda; x y z . x z (y z)<br \/>\n2. K = &lambda; x y . x<br \/>\n3. I = &lambda; x . x<br \/>\nGiven only S and K, you can actually write *any* lambda calculus expression &#8211; and therefore, you can write any computable function using nothing but S and K. I is often added for convenience; it&#8217;s just a shorthand for &#8220;SKK&#8221;.<br \/>\nYou can do recursion in SKI; the Y combinator of lambda calculus is:<br \/>\nY = S S K (S (K (S S (S (S S K)))) K)<br \/>\nUnlambda is based on SKI; but it extends it with a few additional kinds of sugar to make things easier to write. (Nothing makes Unlambda easier to *read*!) The basic idea is that *everything* in unlambda is a function; and in particular, everything is a function that takes a *single* variable: you don&#8217;t need more than one parameter, because you can always using [currying][curry] to express any multiparameter function as a series of single-parameter functions.<br \/>\n(As a refresher, if you have a two-parameter function in lambda calculus, like &#8220;&lambda; x y . x + y&#8221;; *currying* is translating it into a one parameter function that returns a one parameter function: &#8220;&lambda; x .(&lambda; y. x + y)&#8221;.)<br \/>\nThere are eight basic instructions in Unlambda:<br \/>\n1. &#8220;&#8220;&#8221;` : the application operator. &#8220;`&#8217;AB`&#8221; applies the function `A` to the parameter `B`. You can think of this as being something like the &#8220;(&#8221; in Lisp; there is no close paren because since every function takes only one parameter, there is no *need* for a close paren. And hey, adding a syntactically unnecessary close paren would only make the code easier to read, and we can&#8217;t have that!<br \/>\n2. &#8220;`k`&#8221; : the K combinator.<br \/>\n3. &#8220;`s`&#8221; : the S combinator.<br \/>\n4. &#8220;`i`&#8221; : the I combinator.<br \/>\n5. &#8220;`v`&#8221; : a &#8220;drop&#8221; combinator: takes a parameter, discards it, and returns &#8220;`v`&#8221;<br \/>\n6. &#8220;`d`&#8221; : the &#8220;delay&#8221; operator; a way of doing *lazy evaluation* in Unlambda. Unlambda normally evaluates the argument before it<br \/>\napplies a function. `&#8217;dA` is the same thing as `A`, except that `A` isn&#8217;t evaluated until &#8220;`&#8217;dA`&#8221; is applied to something else.<br \/>\n7. &#8220;`c`&#8221; : the &#8220;call-with-current-continuation&#8221; combinator. This is equivalent to [&#8220;call\/cc&#8221;][callcc] in Scheme. What it does is call some function with the current state of the computation captured as a function as its parameter. What this means is that &#8220;`&#8217;cAB`&#8221; calls &#8220;`A`&#8221;. &#8220;`A`&#8221; receives the value &#8220;`cAB`&#8221; as a parameter; during A, it can return a value, *or* it can call the continuation, which will evaluate &#8220;`cAB`&#8221; again. So this is the function-based equivalent of a loop. &#8220;c&#8221; turns the &#8220;loop body&#8221; into a function; so at the end of the loop, you re-invoke the continuation with a new parameter to run the next iteration.<br \/>\n8. &#8220;`.`&#8221; : The &#8220;.&#8221; operator is actually a meta-operator. &#8220;`.x`&#8221; is a function which returns its parameter, *and* prints the character &#8220;x&#8221;.<br \/>\n9. &#8220;`r`&#8221; is a shorthand for &#8220;`.CR`&#8221;, where CR is the carriage return character.<br \/>\nAnd that is it. The entire language.<br \/>\nNote that there are no numbers! We need to build numbers using church numerals.<br \/>\n* The church numeral &#8220;0&#8221; is &#8220;&lambda; f. (&lambda; x . x)&#8221;. In Unlambda, that&#8217;s &#8220;`&#8217;ki`&#8221;.<br \/>\n* The church numeral &#8220;1&#8221; is &#8220;&lambda; f . (&lambda; x . f x)&#8221;; in unlambda, that&#8217;s &#8220;`i`&#8221;.<br \/>\n* The church numeral &#8220;2&#8221;  is &#8220;&lambda; f . (&lambda; x. f f x)&#8221;; or &#8220;`&#8221;s&#8221;s&#8217;kski`&#8221;.<br \/>\n* The church numeral &#8220;3&#8221; is &#8220;&lambda; f . (&lambda; x . f f f x)&#8221;; or &#8220;`&#8221;s&#8221;s&#8217;ksk&#8221;s&#8221;s&#8217;kski`&#8221;.<br \/>\n* And so on.. Just keep appending &#8220;`&#8221;s&#8221;skski`&#8221; for each successive number.<br \/>\nSo&#8230; On to a couple of programs!<br \/>\nHello world in Unlambda is:<br \/>\n`r&#8220;&#8220;&#8220;&#8220;&#8220;`.H.e.l.l.o. .w.o.r.l.di<br \/>\nIt&#8217;s pretty straightforward. It&#8217;s actually sort of easier to understand if you look from right to left. The &#8220;`.H.e.l.l.o&#8230;`&#8221; is basically a series of &#8220;`i`&#8221; combinators, which print out the characters of hello world. The trailing &#8220;`i`&#8221; is there because &#8220;`.d`&#8221; needs a parameter in order to do anything. And the list of &#8220;`&#8217;`&#8221;s at the beginning are there to make the &#8220;.&#8221; functions be applied. Finally, apply &#8220;`&#8217;r`&#8221; to the whole thing &#8211; which prints a newline at the end.<br \/>\nNext, a counter: starts with &#8220;N=1&#8221;; print &#8220;N&#8221; asterisks, add one, and then repeat.<br \/>\n&#8220;r`ci&#8220;s`k`c&#8220;s&#8220;s`ksk`kr.*<br \/>\nIf you look at it, you can see the number pattern in there; &#8220;`&#8221;s&#8221;s&#8217;ksk`&#8221;. That fragment is an SKI function to add one. You capture a continuation for the main iteration; run &#8220;`i&#8221;s&#8217;k&#8217;cN`&#8221;; that&#8217;s a fragment that adds &#8220;1&#8221; to N, and then prints N. Since you&#8217;ve captured the continuation, you can re-invoke it on 1+n; the rest captures *another* continuation which is the inner loop for printing &#8220;*&#8221;s; it does that, and then it invokes the out continuation to go back and do it for &#8220;N+1&#8221;.<br \/>\nOne last, which I&#8217;ll leave for you to trace through yourself: this one generates the fibonacci sequence; and for each element of it, it prints out the numbers using a line of asterisks containing &#8220;N&#8221; asterisks for the number &#8220;N&#8221;:<br \/>\n&#8220;`s&#8220;s&#8220;sii`ki<br \/>\n`k.*&#8220;s&#8220;s`ks<br \/>\n&#8220;s`k`s`ks&#8220;s&#8220;s`ks&#8220;s`k`s`kr&#8220;s`k`sikk<br \/>\n`k&#8220;s`ksk<br \/>\nI&#8217;ll also point out that there are a ton of variants on Unlambda, ranging from the really interesting ([LazyK][lazyk]) to the bizzarely minimal ([Iota][iota]) to the downright goofy ([Jot][jot]).<br \/>\n[callcc]: http:\/\/community.schemewiki.org\/?call-with-current-continuation<br \/>\n[ski]: http:\/\/goodmath.blogspot.com\/2006\/05\/from-lambda-calculus-to-combinator.html<br \/>\n[curry]: http:\/\/goodmath.blogspot.com\/2006\/05\/my-favorite-calculus-lambda-part-1.html<br \/>\n[iota]: http:\/\/ling.ucsd.edu\/~barker\/Iota\/<br \/>\n[lazyk]: http:\/\/homepages.cwi.nl\/~tromp\/cl\/lazy-k.html<br \/>\n[jot]: http:\/\/ling.ucsd.edu\/~barker\/Iota\/#Goedel<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Todays tasty treat: a variable-free nearly-pure functional programming language: Unlambda. Unlambda is based on the SKI combinator calculus. The [SKI calculus][ski] is a way of writing lambda calculus without variables, and without lambda. It&#8217;s based on three combinators: S, K, and I: 1. S = &lambda; x y z . x z (y z) 2. [&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":[92],"tags":[],"class_list":["post-111","post","type-post","status-publish","format-standard","hentry","category-pathological-programming"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p4lzZS-1N","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/111","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=111"}],"version-history":[{"count":0,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/111\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/media?parent=111"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/categories?post=111"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/tags?post=111"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}