Functional Programming Techniques With Ruby: Part II

Share this article

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: [gist id=”2143084″] 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: [gist id=”2143096″] 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: [gist id=”2143108″] 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): [gist id=”2143114″] 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: [gist id=”2143131″] This Method Object again acts just like a Proc, so shock horror, we can pass this into block accepting methods too! [gist id=”2143144″] 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: [gist id=”2143151″] 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! [gist id=”2143157″] 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: [gist id=”2143168″] 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? [gist id=”2143172″] 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? [gist id=”2143187″] 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: [gist id=”2143194″] 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.

Frequently Asked Questions (FAQs) about Functional Programming Techniques with Ruby

What is the significance of functional programming in Ruby?

Functional programming in Ruby is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data. It emphasizes the application of functions, in contrast to the procedural programming approach, which emphasizes changes in state. Functional programming in Ruby can lead to code that is more concise, predictable, and easier to test and debug. It also facilitates parallel programming by eliminating side effects, which can simplify multithreading.

How does higher-order functions work in Ruby?

Higher-order functions are a key feature of functional programming. In Ruby, these are functions that can accept other functions as arguments and/or return functions as results. This capability allows for greater abstraction and modularity in your code. For instance, the map method in Ruby is a higher-order function that takes a function (or a block of code) as an argument and applies it to every element in an array.

What is currying in Ruby and how is it used?

Currying is a technique in functional programming where a function with multiple arguments is transformed into a sequence of functions, each with a single argument. In Ruby, the curry method is used to transform a method into a curried function. This can be useful in situations where you want to generate a sequence of functions for later use, each function taking one argument and returning the next function in the sequence.

How does functional programming in Ruby improve code readability?

Functional programming can improve code readability by reducing the amount of code needed and making it more declarative. Instead of writing detailed step-by-step instructions, you describe what you want to achieve, and the language’s functional programming features take care of how it’s done. This can make the code easier to read and understand, especially for developers who are new to the project.

How does functional programming in Ruby aid in debugging and testing?

Functional programming can make debugging and testing easier because it avoids side effects and mutable data. Functions in functional programming are like mathematical functions: the output depends only on the input, not on any external state. This means that you can test each function independently, and if there’s a bug, you know it’s in the function you’re testing – not in some other part of the program.

Can you provide an example of a higher-order function in Ruby?

Sure, one common example of a higher-order function in Ruby is the map method. Here’s a simple example:

numbers = [1, 2, 3, 4, 5]
squares = numbers.map { |number| number * number }
# squares is now [1, 4, 9, 16, 25]

In this example, map is a higher-order function that takes a block of code (a function) as an argument and applies it to every element in the numbers array.

What are the benefits of using currying in Ruby?

Currying can make your Ruby code more modular and reusable. By breaking down a function that takes multiple arguments into a series of functions that each take a single argument, you can create new functions by providing some of the arguments, and then pass those functions around to be completed later with the remaining arguments. This can lead to more readable and maintainable code.

How does functional programming in Ruby support parallel programming?

Functional programming supports parallel programming by eliminating side effects. Because the output of a function in functional programming depends only on its input, not on any external state, multiple functions can be run in parallel without worrying about them interfering with each other. This can make it easier to write multithreaded code and take full advantage of multi-core processors.

Can functional programming in Ruby be used with other programming paradigms?

Yes, Ruby is a multi-paradigm language, which means it supports several different programming paradigms, including procedural, object-oriented, and functional programming. You can mix and match these paradigms as needed to best solve your particular problem. For example, you might use object-oriented programming to model complex data structures, and then use functional programming techniques to manipulate those data structures.

How can I start using functional programming techniques in my Ruby code?

The best way to start using functional programming techniques in your Ruby code is to start small. Try using higher-order functions like map, reduce, and filter in your code. Experiment with immutable data structures and pure functions that don’t have side effects. As you get more comfortable with these techniques, you can start to use more advanced features like currying and recursion.

Nathan KleynNathan Kleyn
View Author

Hi! I currently work for Intent HQ as Director of Engineering, writing functional Scala by day and Rust by night. I write for SitePoint about Ruby, and I’m on Twitter and on GitHub. You can get in touch with me at mail/at/nathankleyn.com.

functional programming
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week
Loading form