In Progress
Unit 1, Lesson 1
In Progress

Partial Function Application

Functional programming techniques are becoming more and more mainstream. And while Ruby is generally thought of as an object-oriented language, it is designed to enable functional approaches as well.

Two important and related tools from the functional world are currying and partial function application. In today’s episode Joe Leo, co-author of The Well-Grounded Rubyist, joins us to show Ruby’s built-in support for currying and partial application. Enjoy!

Video transcript & code

Currying and Partial Function Application in Ruby

Introduction

Today I'm going to discuss a bit of functional programming, a topic I dive into in the latest edition of The Well-Grounded RubyistObject-oriented programming serves as the foundation of Ruby. But Ruby has always had language features to support functional programming. In fact, Matz is quick to cite Lisp - a functional language - as his biggest influence when he created Ruby.

In the last several years, the Ruby core team has ramped up it's support of FP. Today I'm going to explain two related and helpful concepts: currying and partial function application. My goal is to give you more options when deciding how to design your Ruby programs.

Let's start with currying. The concept of currying comes from mathematician Haskell Brooks Curry. And yes, that is also where the name for the Haskell programming language came from. In mathematics and in computer science, currying is the act of splitting one function with multiple arguments into multiple functions, each with one argument. Here we see a simple `add` function that takes two arguments, `a` and `b`, and adds them together. This is one function with two arguments.

``````
add = -> (a, b) { a + b }
``````

When we call `add`, we simply pass in the two arguments and the sum is returned. Let's try this out. Notice that I'm using the "dot parentheses" syntax, which is shorthand for "dot call" with parentheses.

``````
add = -> (a, b) { a + b }
``````

By contrast `curried_add` is actually two functions chained together. Each individual function takes one argument.

``````
curried_add = -> (a) { -> (b) { a + b } }
``````

We have to call this function differently. We can't simply call `curried_add` with two arguments because we'll get an `ArgumentError`.

We need to call `curried_add` with one argument, and then call the function that is returned with the other argument.

``````
curried_add = -> (a) { -> (b) { a + b } }
curried_add.(1,3) # ArgumentError: wrong number of arguments (given 2, expected 1)
``````

Both `add` and `curried_add` are valid ruby syntax, and both are lambdas. The second function is a curried version of the first.

``````
add = -> (a, b) { a + b } # => #<Proc:0x0000560ebc4b14e8@(irb):1 (lambda)>
curried_add = -> (a) { -> (b) { a + b } } # => #<Proc:0x0000558b006eb820@(irb):2 (lambda)>
``````

In Ruby, we can create the functional equivalent of `curried_add` by using the `curry` method.

Notice that the `curry` method simply returns a lambda, just like our stabby lambda examples above.

In Ruby, the `curry` method gives us some additional flexibility. We can now call `curried_add` with one or two arguments. Let's try calling it both ways.

``````
``````

The result is the same and there are no `ArgumentError`s. This becomes important as we move into partial function application.

``````
``````

Partial function application is a programming technique used when we know some, but not all, of a function's arguments. The function is evaluated with the given arguments and a new function is returned that will accept the rest of the arguments. This can be done repeatedly until all of the required arguments are supplied. Let's use our original `add` function as an example.

``````
add = -> (a, b) { a + b }
``````

We've just created a function using the "stabby lambda" syntax. Just like last time, my `add` function takes two arguments, `a` and `b`, and adds them together. What if I know the value of `a` now but not the value of `b`?

``````
add = -> (a, b) { a + b } # => #<Proc:0x0000560ebc4d8b60@(irb):13 (lambda)>
``````

If I pass in that value for `a` and use partial function application, I will get another function with the value for `a` applied. I now have a function that takes an argument `b` and adds 1 to it.

``````
add_one = -> (b) { 1 + b }
``````

The `curry` method obviates the need to write out most of the function syntax we've seen so far. Thus `add.curry` can give us the partially applied function `add_one`.

``````
add = -> (a, b) { a + b }
``````

When we call `add_one`, we only need to give it one argument. This technique is powerful both because of its conciseness and because of the versatility it allows us.

``````
add = -> (a, b) { a + b }
``````

A common use case of currying and partial function application is creating generic functions that can be reused. Here's a function that takes a value, `x`, and an array and finds multiples of the value within the array.

``````
find_multiples = -> (x, arr) {
arr.select { |el| el % x == 0 }
}
``````

Let's call `find_multiples` a couple of times.

The first time we're looking for multiples of 3 in a given array. The second time we'll look for multiples of 5 with a different array.

``````
find_multiples = lambda do |x, arr|
arr.select { |el| el % x == 0 }
end

find_multiples.(3, [1,3,5,7,9,12]) # => [3, 9, 12]
find_multiples.(5, [3,6,9,12,15]) # => [15]
``````

So what if we want to use `find_multiples` in an object where `x` is already known? We can refine `find_multiples` with partial function application using the `curry` method. `find_multiples_of` is the curried form of `find_multiples`. Now we can pass in the first argument and return a function that takes the remaining argument, an array.

``````
find_multiples_of = find_multiples.curry
``````

Let's make equivalents of the `find_multiples` functions above. We get a pair of new functions that we've created with the help of our generic `find_multiples` function.

``````
find_multiples_of_3 = find_multiples_of.(3)
find_multiples_of_5 = find_multiples_of.(5)
``````

Our new functions now simply take an array.

``````
find_multiples_of_3.([1,3,5,7,9,12])
find_multiples_of_5.([3,6,9,12,15])
``````

``````
find_multiples_of_3.([1,3,5,7,9,12]) # => [3, 9, 12]
find_multiples_of_5.([3,6,9,12,15]) # => [15]
``````

We can call curried or partially applied functions a number of ways. Let's turn again to our simple `add` function, this time adding a third argument.

``````
add = -> (a, b, c) { a + b + c }
``````

Calling `curry` with no arguments simply returns a lambda.

``````
add = -> (a, b, c) { a + b + c }
fun = add.curry # =>  #
``````

We can evaluate the lambda all at once...

``````
fun.(1,2,3) # => 6
``````

...or chain several calls together.

``````
fun.(1).(2).(3) # => 6
``````

Of course if we pass in anything less than the function's arity, we're back to partial function application.

``````
fun2 = fun.(1) # => #
fun2.(2,3) # => 6
``````

Let's make this a little more interesting. We've already seen functions that sum two or three variables. Now let's create a function that sums up an arbitrary number of variables. Using "splat nums," we tell our `sum_all` function to add up however many arguments we pass in.

We can call it with two arguments or ten arguments and `sum_all` will do its job.

``````
sum_all = -> (*nums) { nums.reduce(:+) }
sum_all.(1,2) # => 3
sum_all.(1,2,3,4,5,6,7,8,9,10) # => 55
``````

`sum_all` is a handy function, but it's a little greedy. We can't use partial function application with `sum_all` because no matter how few arguments we supply it will still execute the function. However, we can curry `sum_all` and pass in an optional minimal arity argument. Once we curry a function in this way, the curried object will only be evaluated once the required number of arguments has been supplied. Let's try this with `sum_all` by calling `curry` and supplying a minimum arity of 4. We'll store the result in `sum_at_least_four`. By doing this we are telling Ruby not to evaluate the function until a minimum of four arguments are passed into that function.

``````
sum_at_least_four = sum_all.curry(4)
``````

Now when we call `sum_at_least_four` with only two arguments, we are partially applying `sum_at_least_four`.

``````
sum_at_least_four = sum_all.curry(4)
sum1 = sum_at_least_four.(3,4)
``````

We get our familiar lambda back and we can re-use it. `curry` has given us our generic function superpowers back!

``````
sum_at_least_four = sum_all.curry(4)
sum_two_more = sum_at_least_four.(3,4) # => #
``````

When we supply more arguments to total at least four, Ruby will evaluate the function.

``````
sum_two_more.(5,6) # => 18
sum_two_more.(5,6,10) # => 28
``````

So you see, Ruby makes functional programming fun! Currying and partial function application become a lot easier to understand when you can look at it in the friendly syntax Ruby provides. You are now ready to add another tool to your toolbelt when designing your programs!