Functional Programming with Ruby: Procs, Lambdas, Closures and Functions
Last updated:Functional Programming INTRO
Functional programming is a programming paradigm that emphasizes coding with immutable variables, higher-order functions, avoiding nonlocal side-effects and recursive functions.
From my experience, this definition doesn't help much to understand what it's all about, and you need to play around with functional programming languages (e.g. Haskell or Scala) for the advantages and disadvantages of this method to become apparent. The other, more common programming paradigm is imperative programming which is what you have probably used so far.
That said, it does not mean that you need to pick and choose one paradigm over the other and live with it for better or worse. Many languages (including Ruby) expose tools that allow us to write functional code where it makes sense to do so but does not prohibit the use of normal, imperative programming constructs that most of us are used to.
It is possible to use functional principles in all programming languages.
Ruby block parameters and the yield
keyword
HIgher-order Functions are one of the cornerstones of functional programming, but they're fairly easy to understand. A higher-order function is a function that simply takes a function as parameter or returns a function as its result when called.
Higher order functions are functions that take functions as parameters or return functions as a result
One of the ways Ruby lets you pass functions as arguments is through using blocks. For example, you can use Array#each
as follows:
arr = [1,2,3,4]
arr.each{ |el| print el * 2 }
# prints 2468
and another example with Array#select
for filtering an array:
arr = [1,2,3,4,5,6]
print arr.select{ |el| el % 2 == 0 } # select even numbers
# prints [2, 4]
The block (within curly braces) was effectively passed as a parameter to method each
. You can send a block as a parameter to any method that uses the yield
keyword. Yield
passes control to the block passed as parameter.
A method that only prints a number if it makes the given block return true:
def print_if(number) if yield number print number end end # prints nothing because 4 is not equal to 5 print_if(4){ |el| el == 5 } # prints 4 because 4 is even print_if(4){ |el| el % 2 == 0 } # prints 2 because true is always returned print_if(2){ |el| true }
Procs
Passing blocks are one way to pass functions as arguments to other functions but that's not all Ruby has for you. You can also declare functions and put them into variable and do anything you would with a normal variable or value.
They're called procs in Ruby and this is how you use them:
Sending procs as arguments to functions
# creating a proc that takes two number and returns their sum sum = proc{ |a,b| a+b } # calling the proc res = sum(3,4) print res # prints 7 # the proc is just another parameter def some_function(x,y) # ... end some_function(sum,"foo bar")
Returning procs from functions
# procs can also be returned from functions def proc_generator(multiplier) proc{|num| num * multiplier } end # create a function that multiplies something by three times_three = proc_generator(3) # and use it print times_three(4) # prints 12
There's 3 ways to create a
Proc
in Ruby:Proc.new{}
,proc{}
and alsolambda{}
Extras
You can define you own keywords to declare a block
the
'λ'
character has unicode 3BB
def λ(&blk)
Proc.new(&blk)
end
by_four=λ{|num| num * 4}
puts by_four.call(3) # prints 12
Resources