Ruby Currying
Update: This post was updated to show the difference between Currying and Partial Functions.
Currying is a concept in Functional Programming that's enabled by Higher-order functions. It's best described as: the ability to take a function that accepts n parameters and turns it into a composition of n
functions each of them take 1 parameter. Check this function f which takes 3 params x,y,z
f(x,y,z) = 4*x+3*y+2*z
Currying means that we can rewrite the function as a composition of 3 functions(a function for each param):
f(x)(y)(z) = 2*z+(3*y+(4*x))
The direct use of this is what is called Partial Function where if you have a function that accepts n parameters then you can generate from it one of more functions with some parameter values already filled in. Ruby 1.9 comes with support for currying concept(through the Proc#curry method) and this blog post is explaining how you can use it effectively.
I'm going to walk you through a simple example to explain the concept, however i need to mention few things:
1- The main example is taken from the free Scala By Example book(First-Class Functions chapter), however i have replaced recursion calls by simple upto
iterators.
2- In Ruby 1.9 you can use block.(*args) just like you use block.call(*args)
or block[*args]
in Ruby 1.8, so i'll stick to block.(*)
notation.
3- I could have used the inject
method, but i preferred readability to concise code.
Let's start the simple tutorial by adding three methods:
1- A method to sum all integers between two given numbers a
and b
.
2- A method to sum the squares of all integers between two given numbers a
and b
.
3- A method to to sum the powers 2^n
of all integers n
between two given numbers a
and b
.
Cool, however if you focus on the 3 methods, you will notice that these methods are all instances of a pattern Σf(n) for a range of values a -> b. We can factor out the common pattern by defining a method sum:
Ok, but what about having the formal definitions for the 3 methods? How can we have those definitions out of the sum
method? Well that's the use of currying and partial functions, in our case we just need to pass the first param to the sum
method to specify what type of sum is it:
That's it! I hope I could clarify the use of currying, if not just add your comment here ;)