Functional Programming Techniques With Ruby: Part II

By Nathan Kleyn

Functional Programming Techniques with Ruby

In part one of this series, we looked looked at the basics of functional programming and visited in detail immutability and side-effect free code.

Today, we’re going to look at higher-order functions and currying, two amazingly useful functional style features that Ruby supports with sublime class. To start with, let’s explore the different types of functions in Ruby and their special traits.

Methods, Blocks, Procs, and Lambdas

As you may know, Ruby supports a lot of different types of functions. Blocks, Procs, Methods and Lambdas are all just slight variances of these types in Ruby.The nuances that separate each of them are what make most newcomers to this “function overload” in Ruby throw their hands up in despair. Don’t give in, it’s easier than you might think!

We’ll start with methods, which we all know and love. You use them all the time, they’re quick and easy to declare, and they help us put to use the early principles of subroutine based programming:

def some_method # ... end 

What’s often glossed over with methods in Ruby is that they are not strictly “first class functions” (functions that can be passed around as objects). This code does not work:

While we’d expect to get back as a return value the return_function method we defined by calling some_method, you can see that isn’t the case. Alas, it seems that methods in Ruby are not objects. And thus, we discover why Blocks, Procs and Lambdas are so useful.

Blocks are certainly the most common way to pass around references to functions in Ruby. They open the door to some classy looking DSLs by making it super easy and readable to pass functions as arguments:

On the surface, it may seem that Blocks are just as crippled as methods, in that they can only be used for the limited application of being passed into a function. The breakthrough comes when you realise that, behind the scenes, a Block is actually just a Proc in disguise. In fact, Blocks are just a special syntactic sugar in Ruby to create Procs. You can see that in practice when you use the unary ampersand operator to get access to a Block as an argument in a method:

You can also see it in action when you note you can pass in Proc instances instead of a block, to a block accepting method (you have to use the unary ampersand operator in front of your Proc to make Ruby aware you’re passing it as a Block and not as a normal argument):

Returning for a moment to methods, they are actually just like Blocks in one main respect: they are syntactic sugar for some variation of an underlying Proc. To that end, Ruby actually does give us a way to get a method we’ve defined as an instance of the Method class, so we can get a reference to it that we can pass around:

This Method Object again acts just like a Proc, so shock horror, we can pass this into block accepting methods too!

The last remaining function type to be discussed are Lambdas. What could Lambdas possibly add to this crazy mish-mash of different function types in Ruby? Well, Lambdas again are really just Procs, but with two small, but extremely important differences:

  • Lambdas check the arguments they receive, just like methods. Procs do not. This means if you pass only one argument to a Lambda that takes two arguments, you’ll get an ArgumentError. If you do the same to a Proc, it will just blindly accept the ones you did give, and set the rest of the arguments to nil.
  • Any return statements used in a Proc will also return from the method that called that Proc. Lambdas, on the other hand, will not. This means you can call a Lambda, get its return value, and process it, all within the one method.

So, a quick overview of what we’ve looked at so far:

  • All functions in Ruby act, or can be made to act, like some variant of a Proc.
  • Blocks are really just syntactic sugar for Procs.
  • Lambdas are like Procs, but with stricter argument passing and localised returns.
  • Defined methods can be fetched as Method objects by using the Kernel#method method.
  • Use the & unary operator to signify when you are passing Procs/Lambdas/Methods as a block, and leave the operator off when you are passing them as a normal argument.

Now to put these functions to use!

Higher-order Functions

The concept of higher-order functions is one that is actually surprisingly simple to understand. They are defined as functions that do one or more of the following:

  • Accept a function as an argument.
  • Return a function as the return value.

Now you’re probably thinking, “I can think of a thousand methods in Ruby that do one of those”, and you’d be right! Higher-order functions in Ruby are virtually everywhere; they’re one of Ruby’s most prevailent functional features.

Let’s start one of the more well known methods in Ruby that takes a function as an argument:

An astounding number of the core methods in Ruby that ship out of the box are higher-order functions, as so many of them take Blocks. Methods like map, inject, and each are prime examples.

As for functions that return functions, they’re not so common in Ruby’s core library, but that doesn’t mean you don’t have all the tools at your disposal to do it yourself!

Because we need to return this anonymous function, we’re using a Lambda here, but there is no reason you couldn’t also use a Proc. But what is the real world use of all of this, and how can you make decent use of it in your programs?

The benefits of accepting functions as arguments to other functions is clearly demonstrated by the huge number of examples in the Ruby core library, so we’ll gloss over that style of higher-order functions for now. However, it turns out that the second definition of higher-order functions (being able to return functions from other functions) opens the door to two amazingly useful techniques: “partial function application”, and it’s more well known cousin, “currying”.

Applying Higher-order Functions: Partial Application and Currying

In Ruby 1.9, the Proc class gained one new, and extremely useful method: #curry. This brings partial function application and currying to Ruby. You may have come across currying before, likely when using languages like JavaScript where first-class function support is rife and currying is a relatively well undersood and practiced technique.

Let’s first understand what these two different applications of functions are. Partial function application, and currying, are defined as such:

  • Partial function aplication is calling a function with some number of arguments, in order to get a function back that will take that many less arguments.
  • Currying is taking a function that takes n arguments, and splitting it into n functions that take one argument.

In order to give you a clearer idea of what each of these two things will do a function, let’s take an example Proc:

proc { |x, y, z| x + y + z } 

Partial application of this function would return, if we passed in the first two arguments, the following nested Procs:

proc { |x, y| proc { |z| x + y + z} } 

On the other hand, currying this function would return the following nested Procs:

proc { |x| proc { |y| proc { |z| x + y + z} } } 

Note that you can only pass in one argument at a time to the result of a curried function, but pass as many as you like at a time when using partial application. This is the core principal that defines these two applications. The Proc#curry method in Ruby allows you to execute both of these applications.

Some examples are in order to properly explain this. Let’s say we have the following methods defined in our application:

Looking at this from the perspective of trying to DRY this code up, there’s something seriously wrong here. All these functions take exactly the same arguments, their only difference is the function which they use on the a argument. Perhaps then, we can DRY this up?

But now we have to write out that function name every time?! This doesn’t seem much better.

Proc#curry to the rescue!

What if we could create some helper functions that fix the first argument of #apply_math, and allow us to call our functions using the method names we were using before?

Not only has this allowed us to dry up our code, but it’s also opened the door to doing interesting things down the track. What if we want to create an increment by one function? Easy as pie, with just one extra Proc#curry call:

Functional languages like Haskell have currying and partial function application built right into the language. The feature is extremely useful, and can help you dry up code and keep functions distilled to their bare minimum. A side-effect of working with functions in this way is that your code also becomes much easier to test. Because you have split functions up into smaller, repeatable segments in order to cury them, you can test each function for only what they add on top of the existing functions they curry; this will help you write leaner, cleaner, more concise code and tests, and much more reusable code.

Next Time…

We’ll talk about recursion, and lazy-evaluation! These are staples in functional programming, and once again they’re available to use in many hidden forms within Ruby.

  • francis

    Thank you very much

  • thatrubylove

    Great post! One thing to mention is that blocks, procs, and lambdas return from return and break differently.

    Glad you mentioned procs vs lambdas in arguments.

    My rule is this, blocks are ok, procs are trouble, and lambdas rule.

    Using lambdas over procs I can guarantee that any anon function that returns early will return to the appropriate lexical context.

Get the latest in Ruby, once a week, for free.