Functional Programming
Procs
Proc class is a built-in Ruby object instances of which (procs) are representations of callable blocks of Ruby code. As all other Ruby objects procs can be stored under a variable or a constant, be an array or a hash value or used as a method or a block argument.
Some of ways of creating a proc is using the Proc #new
method or the Kernel #proc
method
my_proc = Proc.new { |x| x }
my_other_proc = proc { |x| x }
To call a proc #call
method is used.
my_proc.call('Great') # => "Great"
In addition, a proc is created when a block is passed as an argument to a method.
Further, a proc of a special kind - namely lambda
- can be created using Kernel #lambda
method or a lambda literal syntax.
Procs as Closures
Procs are closures which mean that they are bound to their identifiers (i.e. self
objects) current at the time of their creation and they carry with them used within their body variable and constant references to objects available in the scope of place in which they were created.
class Bird
def fly
wings = 'feathers'
Proc.new do
puts self
puts wings
end
end
end
class Airplane
def fly
Bird.new.fly.call
end
end
Airplane.new.fly.call
# <Bird:...>
# feathers
Lambdas
There is not separate class for lambdas from Proc. Lambdas are just a special kind of Proc class' instances.
Lambdas are special to other procs in the following manner:
1) return
in lambdas exits only from the lambda itself but not - as is the case for other kind of procs - from a method or another proc from which they are called, 2) lambdas are strict about arguments they accept - just like methods - which is not the case for other kind of procs.
A lambda can be created in two ways: 1) using lambda
reserved word, or 2) a literal syntax ->
.
multiply_by_2 = lambda { |a| a * 2 }
multiply_by_3 = ->(a) { a * 3 }
multiply_by_2.call(5) # => 10
multiply_by_2.call # ArgumentError: wrong number of arguments (given 0, expected 1)
def lets_return
lambda { return 'returned from lambda' }.call
proc { return 'returned from proc' }.call
return 'from block'
end
lets_return # => "returned from proc"
Due to its characteristics lambdas are well suited to be used as arguments to methods or procs which then cauld be described as higher order functions.
To check whether a given proc is a lambda the lambda?
method is used.
Defining Methods with Procs
A method can be defined using a proc.
multiply_by_2 = proc { |a| a * 2 }
define_method(:times_two, &multiply_by_2)
times_two # ArgumentError: wrong number of arguments (given 0, expected 1)
times_two(21) # => 42
Converting to Procs
Ruby objects that have a method to_proc
defined can be converted to procs with &
operator. Symbol, Method and Hash are Ruby built-in classes that have to_proc
method defined out-of-the-box.