#---Proc and Lambda---
Procs and Lambdas are similar to blocks in that they too are anonymous functions.
Which is why we have procs and lambdas. They are proper object representations of a ruby block.
Here’s how you create a block that’s a proc:
one_adder = proc { |x| x + 1 }
p one_adder # #<Proc:0x000000011bd93408 sample2.rb:8>
And here’s how you’ll call this proc that’s assigned to a variable:
p one_adder.call(41) # => 42
You can also call it in these other shorthand ways:
p one_adder.(41) # => 42
p one_adder[41] # => 42
Here’s how you create a block that’s a lambda:
perimeter = lambda { |l, b| 2 * (l + b) }
p perimeter
## #<Proc:0x000000011deb32a0 sample2.rb:11 (lambda)>
p perimeter.(3, 6) # => 18
The words proc
and lambda
in the examples above
are not ruby keywords. They are methods in the
Kernel
module.
You can use the “stabby lambda” syntax ->() {}
to create a lambda concisely:
perimeter = ->(l, b) { 2 * (l + b) }
p perimeter.(3, 6) # => 18
When a function is passed a block, and if that block needs to be passed as argument to yet another function, then you’ll have to convert the passed in block to a proc.
That’s done by capturing the block in a variable
prefixed with &
in the function’s signature.
Function block_to_proc
has no intention of calling the
passed in block for its result.
Instead it just wants to pass it as an argument to
another function truth_teller
.
So it converts the block to a proc and puts it into a
variable a_proc_from_a_block
with this syntax:
&a_proc_from_a_block
def block_to_proc(name, &a_proc_from_a_block)
hi = truth_teller(a_proc_from_a_block)
"block_to_proc says to #{name}: #{hi}"
end
def truth_teller(a_proc)
"#{a_proc.call('Dwayne')}, U can't act"
end
res = block_to_proc('The Rock') do |name|
"hello #{name}"
end
p res
## "block_to_proc says to The Rock: Dwayne, U can't act"
Let’s say the truth_teller
above is re-defined
to work with a block
instead of a proc
, like so:
def truth_teller
"#{yield('Dwayne')}, U can't act"
end
Then, in block_to_proc
, you’ll have to convert the
proc back to block before passing it to
truth_teller
using the same &
syntax quirk:
def block_to_proc(name, &a_proc_from_a_block)
hi = truth_teller(&a_proc_from_a_block)
"block_to_proc says to #{name}: #{hi}"
end
Procs and Lambdas differ in how they treat the
arguments and the keywords return
and break
.
For the most part, you don’t have to worry about this. Just stick with lambdas if you don’t want to be caught by any surprises.
You can use the lambda?
method to find out if a block
is a proc or a lambda:
p proc { 'hi' }.lambda? # => false
p -> { 'hi' }.lambda? # => true
You can create a specific kind of anonymous function
with the to_proc
method on a symbol.
Example:
to_s_fn = :to_s.to_proc
p to_s_fn
## => #<Proc:0x000000012889dba8(&:to_s) (lambda)>
(Yes it’s weird that you’re creating a lambda with a
method called to_proc
.)
And the lambda created like this always takes an argument. So you can call it like this:
p to_s_fn.call(123) # => "123"
The result of calling this lambda is the result of
calling to_s
on the supplied argument 123
.
The lambda just does this: 123.to_s
Which means, :to_s.proc
is just a shortcut for this:
->(x) { x.to_s }
More examples:
even_fn = :even?.to_proc
p even_fn.call(123) # => false
## Same as `123.even?`
upcase_fn = :upcase.to_proc
p upcase_fn.call('ruby examples') # => "RUBY EXAMPLES"
to_proc
WorksWhat’s the purpose of this? Why do we need this?
In Ruby, there’s a common pattern where you iterate over an array of items, and then call a specific method on that item.
Like this:
a1 = [11, 22, 33]
a2 = ['harry', 'ron']
p a1.map { |e| e.to_s }
p a1.find_all { |e| e.even? }
p a2.map { |e| e.upcase }
This pattern is so common that Ruby provides a way to shorthand this:
p a1.map(&:to_s) # => ["11", "22", "33"]
p a1.find_all(&:even?) # => [22]
p a2.map(&:upcase) # => ["HARRY", "RON"]
The way this works syntactically is, when you prefix
any Ruby thing with &
, ruby does specific things:
to_proc
method on the symbol.