-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchap12.html
More file actions
237 lines (179 loc) · 23 KB
/
Copy pathchap12.html
File metadata and controls
237 lines (179 loc) · 23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>12 Appendix: Finding Joy in Combinators</title>
<link href="stylesheet.css" type="text/css" rel="stylesheet" />
</head>
<body>
<div id="leanpub-main">
<h2 section-num="12" id="appendix-finding-joy-in-combinators"><span class="section-number">12 </span>Appendix: Finding Joy in Combinators</h2>
<p>In this book, we have looked at a few interesting combinators and some Ruby code inspired by them. Today we’ll review the definition of a combinator, and from there we’ll learn something intriguing about an entire family of programming languages, the <a href="http://en.wikipedia.org/wiki/Concatenative_programming_language" title="Concatenative programming language - Wikipedia, the free encyclopedia">Concatenative Languages</a>.</p>
<p>Let’s start at the beginning: What is a combinator? </p>
<p>One definition of a combinator is <em>a function with no free variables</em>. Another way to put it is that a combinator is a function that takes one or more arguments and produces a result without introducing anything new. In Ruby terms, we are talking about blocks, lambdas or methods that do not call anything except what has been passed in.</p>
<p>So if I tell you that:</p>
<div class="code-block">
<div class="highlight"><pre><code class="n">finch</code><code class="p">.</code><code class="n">call</code><code class="p">(</code><code class="n">a</code><code class="p">).</code><code class="n">call</code><code class="p">(</code><code class="n">b</code><code class="p">).</code><code class="n">call</code><code class="p">(</code><code class="n">c</code><code class="p">)</code>
<code class="p">=</code><code class="o">></code> <code class="n">c</code><code class="p">.</code><code class="n">call</code><code class="p">(</code><code class="n">b</code><code class="p">).</code><code class="n">call</code><code class="p">(</code><code class="n">a</code><code class="p">)</code>
</pre></div>
</div>
<p>Then you know that <code>finch</code> is a combinator because the effect it produces is made up solely of combining the effects of the things it takes as parameters. That’s easy, but yet… Where is our vaunted simplicity? Working with Ruby’s lambdas and braces and calls gets in our way. We can learn a lot from combinatorial logic to help our Ruby programming, but Ruby is a terrible language for actually learning about combinatorial logic.</p>
<h3 section-num="12.1" id="languages-for-combinatorial-logic"><span class="section-number">12.1 </span>Languages for combinatorial logic</h3>
<p>Combinatorial logicians use a much simpler, direct syntax for writing expressions:</p>
<div class="code-block">
<div class="highlight"><pre><code class="n">Fabc</code> <code class="p">=</code><code class="o">></code> <code class="n">cba</code>
</pre></div>
</div>
<p>Whenever a logician writes <code>abc</code>, he means the same thing as when a Rubyist writes <code>a.call(b).call(c)</code>. Note that like Ruby, the precedence in combinatorial logic is to the left, so <code>abc</code> is equivalent to <code>(ab)c</code> just as in Ruby <code>a.call(b).call(c)</code> is equivalent to <code>(a.call(b)).call(c)</code>.</p>
<p>I think you’ll agree that <code>abc</code> is much simpler than <code>a.call(b).call(c)</code>. Here’s another look at the combinators we’ve met in this series, using the simpler syntax:</p>
<div class="code-block">
<div class="highlight"><pre><code class="n">Kxy</code> <code class="p">=</code><code class="o">></code> <code class="n">x</code>
<code class="n">Txy</code> <code class="p">=</code><code class="o">></code> <code class="n">yx</code>
<code class="n">Cxyz</code> <code class="p">=</code><code class="o">></code> <code class="n">xzy</code>
<code class="n">Q3xyz</code> <code class="p">=</code><code class="o">></code> <code class="n">z</code><code class="p">(</code><code class="n">xy</code><code class="p">)</code> # <code class="n">Q3</code> <code class="n">is</code> <code class="n">shorthand</code> <code class="k">for</code> <code class="n">the</code> <code class="n">Quirky</code> <code class="n">bird</code>
<code class="n">Bxyz</code> <code class="p">=</code> <code class="n">x</code><code class="p">(</code><code class="n">yz</code><code class="p">)</code>
<code class="n">Qxyz</code> <code class="p">=</code> <code class="n">y</code><code class="p">(</code><code class="n">xz</code><code class="p">)</code> # <code class="n">Q</code> <code class="n">is</code> <code class="n">shorthand</code> <code class="k">for</code> <code class="n">the</code> <code class="n">Queer</code> <code class="n">bird</code>
</pre></div>
</div>
<p>There are many, many more combinators, of course. Infinitely more, in fact. We only have names for some of the most useful. For example, the Warbler Twice Removed, or <code>W**</code> is written:</p>
<div class="code-block">
<div class="highlight"><pre><code class="n">W</code><code class="o">**</code><code class="n">xyzw</code> <code class="p">=</code><code class="o">></code> <code class="n">xyzww</code>
</pre></div>
</div>
<p>(Warblers are actually in a whole ‘nother family of birds that introduce <em>duplication</em>. Other members of that family include the Mockingbird and Starling. They’re incredibly useful for introducing ideas like iteration and recursion.)</p>
<p>You could say that combinators take a string of symbols (like x, y, z, w, and so forth), then they introduce some erasing, some duplication, some permutation, and add some parentheses. That they work to rearrange our string of symbols.</p>
<p>We have seen that parentheses are allowed, and that some combinators introduce parentheses. Before you say that the combinators introduce new symbols, remember that parentheses are <em>punctuation</em>. If you think of the symbols as words and the parentheses as punctuation, you see that the combinators simply rearrange the words and change the punctuation without introducing new words.</p>
<p>Now I said that combinators work with strings of symbols. This was a terrible analogy, because it made us talk about punctuation and why parentheses are not symbols. Another thing you could say is that combinator work with <em>lists</em> of symbols, then they re-arrange the symbols, including removing symbols, introducing sub-lists, and duplicating symbols.</p>
<p>This is more interesting! Now we can see that in our notation, adding parentheses is a way of introducing a sub list. Let’s revisit the bluebird:</p>
<div class="code-block">
<div class="highlight"><pre><code class="n">Bxyz</code> <code class="p">=</code> <code class="n">x</code><code class="p">(</code><code class="n">yz</code><code class="p">)</code>
</pre></div>
</div>
<p>Now what we can say is this: The bluebird takes a list of three symbols and answers a list of one symbol and a sublist of two symbols. In Ruby:</p>
<div class="code-block">
<div class="highlight"><pre><code class="n">bluebird</code> <code class="p">=</code> <code class="n">lambda</code> <code class="p">{</code> <code class="o">|*</code><code class="n">args</code><code class="o">|</code>
<code class="n">x</code><code class="p">,</code> <code class="n">y</code><code class="p">,</code> <code class="n">z</code> <code class="p">=</code> <code class="n">args</code>
<code class="p">[</code><code class="n">x</code><code class="p">,</code> <code class="p">[</code><code class="n">y</code><code class="p">,</code> <code class="n">z</code><code class="p">]]</code>
<code class="p">}</code>
<code class="n">bluebird</code><code class="p">.</code><code class="n">call</code><code class="p">(:</code><code class="n">x</code><code class="p">,</code> <code class="p">:</code><code class="n">y</code><code class="p">,</code> <code class="p">:</code><code class="n">z</code><code class="p">)</code>
<code class="p">=</code><code class="o">></code> <code class="p">[:</code><code class="n">x</code><code class="p">,</code> <code class="p">[:</code><code class="n">y</code><code class="p">,</code> <code class="p">:</code><code class="n">z</code><code class="p">]]</code>
</pre></div>
</div>
<p>This is easy. What about the Thrush?</p>
<div class="code-block">
<div class="highlight"><pre><code class="n">thrush</code> <code class="p">=</code> <code class="n">lambda</code> <code class="p">{</code> <code class="o">|*</code><code class="n">args</code><code class="o">|</code>
<code class="n">x</code><code class="p">,</code> <code class="n">y</code> <code class="p">=</code> <code class="n">args</code>
<code class="p">[</code><code class="n">y</code><code class="p">,</code> <code class="n">x</code><code class="p">]</code>
<code class="p">}</code>
<code class="n">thrush</code><code class="p">.</code><code class="n">call</code><code class="p">(:</code><code class="n">x</code><code class="p">,</code> <code class="p">:</code><code class="n">y</code><code class="p">)</code>
<code class="p">=</code><code class="o">></code> <code class="p">[:</code><code class="n">y</code><code class="p">,</code> <code class="p">:</code><code class="n">x</code><code class="p">]</code>
</pre></div>
</div>
<p>Now let’s pause for a moment. Imagine we had an entire programming language devoted to this style of programming. The primary thing it does is define combinators that take a list of symbols and recombine them. Since it works with lists and we are thinking about combinatory logic, we will represent our expressions as lists:</p>
<div class="code-block">
<div class="highlight"><pre><code class="n">idiot</code> <code class="o">:</code><code class="n">x</code>
<code class="o">=></code> <code class="o">:</code><code class="n">x</code>
<code class="n">mockingbird</code> <code class="o">:</code><code class="n">x</code>
<code class="o">=></code> <code class="o">:</code><code class="n">x</code> <code class="o">:</code><code class="n">x</code>
<code class="n">bluebird</code> <code class="o">:</code><code class="n">x</code> <code class="o">:</code><code class="n">y</code> <code class="o">:</code><code class="n">z</code>
<code class="o">=></code> <code class="o">:</code><code class="n">x</code> <code class="o">[:</code><code class="n">y</code> <code class="o">:</code><code class="n">z</code><code class="o">]</code>
<code class="n">thrush</code> <code class="o">:</code><code class="n">x</code> <code class="o">:</code><code class="n">y</code>
<code class="o">=></code> <code class="o">:</code><code class="n">y</code> <code class="o">:</code><code class="n">x</code>
</pre></div>
</div>
<p>Wait! Do not shout Lisp! Just because we have lists of things does not mean we are programming in Lisp!! Let’s keep going, and you will see in the next example that I do not mean Lisp:</p>
<div class="code-block">
<div class="highlight"><pre><code class="n">bluebird</code> <code class="n">thrush</code> <code class="p">:</code><code class="n">x</code> <code class="p">:</code><code class="n">y</code> <code class="p">:</code><code class="n">z</code>
<code class="p">=</code><code class="o">></code> <code class="n">thrush</code> <code class="p">[:</code><code class="n">x</code> <code class="p">:</code><code class="n">y</code><code class="p">]</code> <code class="p">:</code><code class="n">z</code>
<code class="p">=</code><code class="o">></code> <code class="p">:</code><code class="n">z</code> <code class="p">[:</code><code class="n">x</code> <code class="p">:</code><code class="n">y</code><code class="p">]</code>
</pre></div>
</div>
<p>And therefore in our fictitious language we can write:</p>
<div class="code-block">
<div class="highlight"><pre><code class="n">quirky</code> <code class="p">=</code> <code class="n">bluebird</code> <code class="n">thrush</code>
</pre></div>
</div>
<p>And thus:</p>
<div class="code-block">
<div class="highlight"><pre><code class="n">quirky</code> <code class="o">:</code><code class="n">x</code> <code class="o">:</code><code class="n">y</code> <code class="o">:</code><code class="n">z</code>
<code class="o">=></code> <code class="o">:</code><code class="n">z</code> <code class="o">[:</code><code class="n">x</code> <code class="o">:</code><code class="n">y</code><code class="o">]</code>
</pre></div>
</div>
<p>This looks familiar. Have you ever written a program in <a href="http://en.wikipedia.org/wiki/PostScript" title="PostScript - Wikipedia, the free encyclopedia">Postscript</a>? Or [Forth](http://en.wikipedia.org/wiki/Forth_(programming_language)? What if instead of using a thrush we used a word called <code>swap</code>? Or instead of a mockingbird we used a word called <code>dup</code>?</p>
<h3 section-num="12.2" id="concatenative-languages"><span class="section-number">12.2 </span>Concatenative languages</h3>
<p>Concatenative (or stack-based) programming languages–like Postscript, Forth, <a href="http://www.factorcode.org/" title="Factor programming language">Factor</a>, and <a href="http://www.latrobe.edu.au/philosophy/phimvt/joy/j00ovr.htmll">Joy</a>–are almost direct representations of combinatorial logic. There is a list of things, words or combinators permute the list of things, and the things can be anything: data, other combinators, or even programs. These languages are called concatenative languages because the primary way to compose programs and combinators with each other is to concatenate them together, like we did with the bluebird and thrush above.</p>
<blockquote>
<p>For me the purpose of life is partly to have joy. Programmers often feel joy when they can concentrate on the creative side of programming, So Ruby is designed to make programmers happy.
–Yukihiro Matsumoto</p>
</blockquote>
<p>You have probably heard that it is a good idea to learn a new programming language every year. Is a concatenative language on your list of languages to learn? No? Well, here is the reason to learn a concatenative language: <em>You will learn to think using combinatorial logic</em>. For example, the Y Combinator is expressed in Joy as:</p>
<div class="code-block">
<div class="highlight"><pre><code class="p">[</code><code class="n">dup</code> <code class="n">cons</code><code class="p">]</code> <code class="n">swap</code> <code class="n">concat</code> <code class="n">dup</code> <code class="n">cons</code> <code class="nb">i</code>
</pre></div>
</div>
<p>Where <code>dup</code> is a mockingbird, <code>swap</code> is a thrush, <code>i</code> is an idiot bird, and <code>cons</code> and <code>concat</code> are likewise two other combinators. Writing in Joy is writing directly in combinators.</p>
<p>In other programming languages, combinatorial logic is an underpinning. It helps us explain and prove certain things, It inspires us to invent certain things. It is behind everything we do. That’s good. But in a concatenative language, it is not an underpinning or behind a curtain. It is right out there in front of you. And learning to program in a concatenative language means learning to think in combinators.</p>
<p>The combinators we’ve discussed in depth so far are all fascinating, however as a basis for writing programs they are incomplete. You cannot represent every possible program using kestrels, thrushes, cardinals, quirky birds, bluebirds, and queer birds. To represent all possible programs, we need to have at least one combinator that duplicates symbols, like a mockingbird or another from its family.</p>
</div>
<div id="leanpub-toc">
<h2>Table of Contents</h2>
<ol class="toc">
<li class="section"><a href="chap00.html#the-mit-license"><span class="section-number">0.1 </span>The MIT License</a></li>
<li class="section"><a href="chap00.html#preface"><span class="section-number">0.2 </span>Preface</a></li>
<li class="chapter"><a href="chap01.html#introduction"><span class="section-number">1 </span>Introduction</a></li>
<li class="chapter"><a href="chap02.html#kestrels"><span class="section-number">2 </span>Kestrels</a></li>
<li class="section"><a href="chap02.html#object-initializer-blocks"><span class="section-number">2.1 </span>Object initializer blocks</a></li>
<li class="section"><a href="chap02.html#inside-an-idiomatic-ruby-kestrel"><span class="section-number">2.2 </span>Inside, an idiomatic Ruby Kestrel</a></li>
<li class="section"><a href="chap02.html#the-enchaining-kestrel"><span class="section-number">2.3 </span>The Enchaining Kestrel</a></li>
<li class="section"><a href="chap02.html#the-obdurate-kestrel"><span class="section-number">2.4 </span>The Obdurate Kestrel</a></li>
<li class="section"><a href="chap02.html#kestrels-on-rails"><span class="section-number">2.5 </span>Kestrels on Rails</a></li>
<li class="section"><a href="chap02.html#rewriting-returning-in-rails"><span class="section-number">2.6 </span>Rewriting “Returning” in Rails</a></li>
<li class="chapter"><a href="chap03.html#the-thrush"><span class="section-number">3 </span>The Thrush</a></li>
<li class="section"><a href="chap03.html#let"><span class="section-number">3.1 </span>Let</a></li>
<li class="chapter"><a href="chap04.html#songs-of-the-cardinal"><span class="section-number">4 </span>Songs of the Cardinal</a></li>
<li class="section"><a href="chap04.html#building-a-cardinal-in-ruby"><span class="section-number">4.1 </span>Building a Cardinal in Ruby</a></li>
<li class="chapter"><a href="chap05.html#quirky-birds-and-meta-syntactic-programming"><span class="section-number">5 </span>Quirky Birds and Meta-Syntactic Programming</a></li>
<li class="section"><a href="chap05.html#a-limited-interpretation-of-the-quirky-bird-in-ruby"><span class="section-number">5.1 </span>A limited interpretation of the Quirky Bird in Ruby</a></li>
<li class="section"><a href="chap05.html#embracing-the-quirky-bird"><span class="section-number">5.2 </span>Embracing the Quirky Bird</a></li>
<li class="section"><a href="chap05.html#andand-even-more"><span class="section-number">5.3 </span>Andand even more</a></li>
<li class="chapter"><a href="chap06.html#aspect-oriented-programming-in-ruby-using-combinator-birds"><span class="section-number">6 </span>Aspect-Oriented Programming in Ruby using Combinator Birds</a></li>
<li class="section"><a href="chap06.html#giving-methods-advice"><span class="section-number">6.1 </span>Giving methods advice</a></li>
<li class="section"><a href="chap06.html#the-super-keyword-perhaps-youve-heard-of-it"><span class="section-number">6.2 </span>The super keyword, perhaps you’ve heard of it?</a></li>
<li class="section"><a href="chap06.html#the-queer-bird"><span class="section-number">6.3 </span>The Queer Bird</a></li>
<li class="chapter"><a href="chap07.html#mockingbirds"><span class="section-number">7 </span>Mockingbirds</a></li>
<li class="section"><a href="chap07.html#duplicative-combinators"><span class="section-number">7.1 </span>Duplicative Combinators</a></li>
<li class="section"><a href="chap07.html#recursive-lambdas-in-ruby"><span class="section-number">7.2 </span>Recursive Lambdas in Ruby</a></li>
<li class="section"><a href="chap07.html#recursive-combinatorics"><span class="section-number">7.3 </span>Recursive Combinatorics</a></li>
<li class="section"><a href="chap07.html#recursive-combinators-in-idiomatic-ruby"><span class="section-number">7.4 </span>Recursive Combinators in Idiomatic Ruby</a></li>
<li class="section"><a href="chap07.html#the-mockingbird"><span class="section-number">7.5 </span>The Mockingbird</a></li>
<li class="chapter"><a href="chap08.html#refactoring-methods-with-recursive-combinators"><span class="section-number">8 </span>Refactoring Methods with Recursive Combinators</a></li>
<li class="section"><a href="chap08.html#divide-and-conquer"><span class="section-number">8.1 </span>Divide and Conquer</a></li>
<li class="section"><a href="chap08.html#the-merge-sort"><span class="section-number">8.2 </span>The Merge Sort</a></li>
<li class="section"><a href="chap08.html#separating-declaration-from-implementation"><span class="section-number">8.3 </span>Separating Declaration from Implementation</a></li>
<li class="section"><a href="chap08.html#practical-recursive-combinators"><span class="section-number">8.4 </span>Practical Recursive Combinators</a></li>
<li class="section"><a href="chap08.html#spicing-things-up"><span class="section-number">8.5 </span>Spicing things up</a></li>
<li class="section"><a href="chap08.html#building-on-a-legacy"><span class="section-number">8.6 </span>Building on a legacy</a></li>
<li class="section"><a href="chap08.html#seriously"><span class="section-number">8.7 </span>Seriously</a></li>
<li class="section"><a href="chap08.html#separating-implementation-from-declaration"><span class="section-number">8.8 </span>Separating Implementation from Declaration</a></li>
<li class="section"><a href="chap08.html#a-really-simple-recursive-combinator"><span class="section-number">8.9 </span>A Really Simple Recursive Combinator</a></li>
<li class="chapter"><a href="chap09.html#you-cant-be-serious"><span class="section-number">9 </span>You can’t be serious!?</a></li>
<li class="section"><a href="chap09.html#string-to-proc"><span class="section-number">9.1 </span>String to Proc</a></li>
<li class="section"><a href="chap09.html#the-message"><span class="section-number">9.2 </span>The Message</a></li>
<li class="chapter"><a href="chap10.html#the-hopelessly-egocentric-book-chapter"><span class="section-number">10 </span>The Hopelessly Egocentric Book Chapter</a></li>
<li class="section"><a href="chap10.html#object-oriented-egocentricity"><span class="section-number">10.1 </span>Object-oriented egocentricity</a></li>
<li class="chapter"><a href="chap11.html#bonus-chapter-separating-concerns-in-coffeescript-using-aspect-oriented-programming"><span class="section-number">11 </span>Bonus Chapter: Separating Concerns in Coffeescript using Aspect-Oriented Programming</a></li>
<li class="chapter"><a href="chap12.html#appendix-finding-joy-in-combinators"><span class="section-number">12 </span>Appendix: Finding Joy in Combinators</a></li>
<li class="section"><a href="chap12.html#languages-for-combinatorial-logic"><span class="section-number">12.1 </span>Languages for combinatorial logic</a></li>
<li class="section"><a href="chap12.html#concatenative-languages"><span class="section-number">12.2 </span>Concatenative languages</a></li>
<li class="chapter"><a href="chap13.html#appendix-source-code"><span class="section-number">13 </span>Appendix: Source Code</a></li>
<li class="section"><a href="chap13.html#kestrels-1"><span class="section-number">13.1 </span>kestrels</a></li>
<li class="section"><a href="chap13.html#thrushes"><span class="section-number">13.2 </span>thrushes</a></li>
<li class="section"><a href="chap13.html#the-cardinal"><span class="section-number">13.3 </span>the cardinal</a></li>
<li class="section"><a href="chap13.html#quirky-birds"><span class="section-number">13.4 </span>quirky birds</a></li>
<li class="section"><a href="chap13.html#bluebirds"><span class="section-number">13.5 </span>bluebirds</a></li>
<li class="chapter"><a href="chap14.html#about-the-author"><span class="section-number">14 </span>About The Author</a></li>
<li class="section"><a href="chap14.html#contact"><span class="section-number">14.1 </span>contact</a></li>
</ol>
</div>
</body>
</html>