There will be Ruby in the middle of this blog post. But first, a tangent in which we explore the lambda calculus. Don’t worry too much about being lost in this next section; we’ll fix that immediately afterward.
There is a programming language named the lambda calculus. It’s
rather minimal: an expression, E, is one of three
things:
V, like a, b,
or cλV.EE EFor example, the identity function is written:
λx.x
And a function that takes two arguments and produces the first is written:
λx.λy.x
You might want to try it out interactively.
We can encode numbers using this programming language, with some creativity. For example, this is the number zero:
λf.λx.x
And this is one:
λf.λx.f x
And this is two:
λf.λx.f f x
And so on. We can even add them, using this addition expression:
λm.λn.λf.λx.m f (n f x)
(This is far too tangental, but this definition of numbers and addition is an early example of object-oriented programming.)
For example, to add the number one and the number two, we’d write this:
(λm.λn.λf.λx.m f (n f x)) (λf.λx.f x) (λf.λx.f f x)
There is an oft-included “extension” to the lambda calculus that might help: naming. Let’s add this expression to our language:
VALUE ≡ ESo now we can write:
ONE ≡ λf.λx.f x
TWO ≡ λf.λx.f f x
ADD ≡ λm.λn.λf.λx.m f (n f x)
THREE ≡ ADD ONE TWO
Here is another case, in another programming language, where naming is useful:
User.where('admin').each do |user|
user.articles.where('published_at IS NULL').each do |article|
article.update_attributes(published_at: Time.now)
end
end
Here it is after introducing some names:
User.admins.each(&:publish_articles)
And here it is after a further simplification:
User.publish_admin_articles
In the first naming section, we named concrete nouns; in the second, we named verbs. Let us now name a concept:
class SignUp
def initialize(params)
@account_params = params[:account]
@user_params = params[:user]
@credit_card_params = params[:credit_card]
end
def run
account = Account.new(@account_params)
if account.save
user = User.new(@user_params.merge(account: account))
if user.save
credit_card = CreditCard.new(@credit_card_params.merge(user: user))
if credit_card.charge
user.charged
end
end
end
end
end
Above we have named the concept of signing up, and given it behavior. We can name even more concepts: merging two users, generating flash messages, processing image files, building a model of a couch.

The average human vocabulary is around 10000 words. While the jury is still out on what the maximum number is, we can all agree that keeping the number of names low is useful for keeping all of an app in your head at once.
There is another trick for more easily understanding an app: a
common vocabulary. When you see a User model, you know
what it means; when you see an Enrichment class, that’s
puzzling. By naming more things uniquely, you have reduced the
vocabulary overhead.
Or is this a red herring? Another way to keep the vocabulary low is to
name everything, but have very few things to name. Push stuff into
frameworks, libraries, and APIs when possible, and out of scope
otherwise. You ain’t gonna need that Bracelet class.
The idea of a common vocabulary is enticing. User, article, comment, controller, singleton, and enumeration are all names we Rails developers understand. Monad, cut, disjunction, pointer—those are other people’s vocabularies. But what if …
What if we outgrew our vocabulary and started poaching theirs? And not like how we poached “functional test” and “closure”—I mean actually use their words the way they are defined.
What if instead of this …
def map(&f = lambda {|x| x})
accumulation = []
each do |element|
accumulation << f.call(element)
end
accumulation
end
… we wrote this:
def map(&f = id)
inject([]) do |accumulation, element|
accumulation + [f.call(element)]
end
end
Heck, what if we went further and wrote this:
def map(&f = id)
inject(empty) do |accumulation, element|
accumulation + wrap(f.call(element))
end
end
This uses a method Kernel#id to name the common
lambda {|x| x}
abstraction; a method empty that produces the empty version of whatever
object this Enumerable is mixed into; and a similarly-defined method,
wrap, that
projects the given object into the Enumerable. Now it produces arrays,
linked lists, sets, tries, maybes,
and so on, as needed.
And now we can use the names identity function, functor, and monoid, too.
Just as our lambda calculus example was greatly simplified by naming our functions, our way-too-long methods can be improved by naming our methods. As with anything, though, there is a trade-off that you must carefully consider.
Here’s an example of some code with very few names:
def acquire_access_token_for(c)
res = Net::HTTP.start('github.com', 443, use_ssl: true) do |http|
r = Net::HTTP::Post.new('/login/oauth/access_token')
r.set_form_data('client_id' => '1234123',
'client_secret' => 'basdu9as',
'code' => c)
http.request(req)
end
case res
when Net::HTTPsuccess
b = res.body
if b['access_token'].any?
b['access_token'].first
else
raise b['error'].first
end
else
raise res.inspect
end
end
Here’s the same example, with more names:
def acquire_access_token_for(code)
access_token_response = access_token_post(code)
case access_token_response
when Net::HTTPsuccess
extract_access_token_from(access_token_response)
else
handle_access_token_failure(access_token_response.message)
end
end
private
GITHUB_CLIENT_ID = '1234123'
GITHUB_SECRET = 'basdu9as'
def access_token_post(code)
Net::HTTP.start(*http_connection) do |http|
request = Net::HTTP::Post.new(github_access_token_path)
request.set_form_data('client_id' => GITHUB_CLIENT_ID,
'client_secret' => GITHUB_SECRET,
'code' => code)
http.request(request)
end
end
def http_connection
[
github_access_token_uri.host,
github_access_token_uri.port,
use_ssl: true
]
end
def github_access_token_path
github_access_token_uri.path
end
def github_access_token_uri
URI.parse(github_access_token_url)
end
def github_access_token_url
'https://github.com/login/oauth/access_token'
end
def extract_access_token_from(successful_http_response)
body = CGI.parse(successful_http_response.body)
if body['access_token'].any?
body['access_token']
else
handle_access_token_failure(body['error'].first)
end
end
def handle_access_token_failure(error_message)
raise error_message
end
As you can see, there’s a trade-off: on the one hand, you can now read it with ease, debug more easily, and have a vocabulary with which to discuss it with others. On the other hand, it takes more vertical space.
Naming is the most powerful abstraction possible. By naming something, you give other people the ability to build atop it. By re-using a name you build a common vocabulary, encouraging more people to build. Naming turns a blob of code into a sequence of patterns. Giving a name to something develops it into a concept with analogies.
So, name it.
Let’s talk about Enumerable#inject. It’s special to me. In other cultures it’s called foldl, foldLeft, reduce, catamorphism, or bananas (PDF). We got our name from Smalltalk, which got it from, I dunno, a folk song?
Inject is an abstraction over structural recursion. For examples, imagine a list were defined like this:
class EmptyList
end
class ConsList
def initialize(first, rest)
@first = first
@rest = rest
end
end
factorials = ConsList.new(1,
ConsList.new(2,
ConsList.new(6,
ConsList.new(24,
ConsList.new(120, EmptyList.new)))))
Computing the length of the list is simple:
class EmptyList
def length
0
end
end
class ConsList
def length
1 + @rest.length
end
end
Computing the product of the list is simple, too:
class EmptyList
def product
1
end
end
class ConsList
def product
@first * @rest.product
end
end
There’s a common pattern here: we have a base case (0 and 1), an enumerable (EmptyList and ConsList), and a combining method (lambda {|x,xs| 1 + xs} and Fixnum#*). Let’s write a method to abstract over this:
class EmptyList
def inject(base, &block)
base
end
end
class ConsList
def inject(base, &block)
block.call(@first, @rest.inject(base, &block))
end
end
Now that we’ve abstracted this out (in 2009 we said “DRYed this up”, and then immediately punched ourselves in the face) we can use it:
class ConsList
def length
inject(0){|_, count| 1 + count}
end
def product
inject(1){|number, running_product| number * running_product}
end
end
(Note that Ruby got the arguments backward. Oh well.)
An underlying theme to inject is that there exists a class with a base case and a combining method. Some other examples are:
0 and Fixnum#+1 and Fixnum#*[] and Array#pushtrue and &&lambda{|x|x} and lambda{|f, g| lambda{|x| f(g(x))}} (the identity method and method composition)… and so on. These are called monoids, and that’s awesome because now we have a name for them.
“Oh sure, just inject over the method monoid,” you say to your coworker, and she’s like, “oh, duh” and types it out:
class Composition
def initialize(f, g)
@f = f
@g = g
end
def compose(g)
Composition.new(self, g)
end
def call(x)
@f.call(@g.call(x))
end
end
id = lambda{|x| x}
twice_the_sine_plus_one = [lambda{|x| x+1}, lambda{|x| x*2}, lambda{|x| Math.sin(x)}]
new_method = twice_the_sine_plus_one.inject(Composition.new(id, id)) do |result, f|
result.compose(f)
end
Join me next time when I talk about monoids closed over the category of endofunctors!