The following are some of notes about Ruby's proc and lambda:
- Function composition in mathmetics
- Blocks (of code) in Ruby (normal blocks, procs & lambdas)
Function Composition in Mathmetics
In Ruby, a composite proc/lambda is an example of function composition. On Wikipedia, the definition goes by the following:
In mathematics, function composition is an operation that takes two functions f and g and produces a function h such that h(x) = g(f(x)).
# Ruby's lambda equivalent of
# h(x) = g(f(x)) = (g ∘ f)(x)
f = ->(x) { x + 1 }
g = ->(x) { puts x }
h = ->(x) { g.(f.(x)) }
h.(1) # prints 2I see the above as if someone were "hitting combo" with the two functions, f and g. Function f gets executed first, then function g carries on and process function f's output. And the order goes from inside out and on.
Blocks in Ruby
def x
# "yield" yields block attached to method "x", if any
yield
end
# Make block 2 ways
# Note there's slight difference in precedence of code execution
# 1. With curly braces
foos.each { |foo| puts foo }
# 2. With "do...end"
bars.each do |bar|
puts bar
endA block, or closure in other programming languages, can NOT "survive" on its own in Ruby. It has to be attached to an object, i.e., variables or methods, or in the form of a proc/lambda.
{ puts 1 } # gets "SyntaxError"
do puts 1 end # gets "SyntaxError"Do you know there is difference between using
{ ... }anddo ... endblock? Check out my blog post Difference between "" & "do...end" in Ruby!
Proc and Lambda
- Definition by ruby-doc.org
A procedure object, or proc, is an encapsulation of a block (of code), which can be stored in a local variable, passed to a method or another proc, and can be called.
Proc
-
Ways to create a proc (courtesy of A Guide to Function Composition in Ruby)
# Use the Proc class constructor double = Proc.new { |number| number * 2 } # Use the Kernel#proc method as a shorthand double = proc { |number| number * 2 } # Receive a block as an argument (note the &) def make_proc(&block) block end double = make_proc { |number| number * 2 } # Use Proc.new to capture a block passed to a method without an # explicit block argument def make_proc Proc.new end double = make_proc { |number| number * 2 } -
Ways to call a proc (courtesy of A Guide to Function Composition in Ruby)
double.call(2) # => 4 double.(2) # => 4 double[2] # => 4 double === 2 # => 4
Lambda - Proc with Flavor
-
Ways to create a lambda (courtesy of A Guide to Function Composition in Ruby)
# Use Kernel#lambda double = lambda { |number| number * 2 } # Use the Lambda literal syntax (more elegant) double = ->(number) { number * 2 } -
Ways to call a lambda
Same as proc's
Lambda vs. Proc
Summarized from Lambda and Non-Lambda Semantics.
| Scenario | Proc | Lambda |
|---|---|---|
a.) When there is a return on the inside... | Jumps out and end the embracing function (function that called the proc) | ONLY jumps out of the block |
| b.) When being fed on extra args... | NO ERROR raised | ArgumentError |
| c.) When there is not enough args... | Missing args will be substituted with nil | ArgumentError |
| If the last arg entered is an array, it will be broken down to fit the missing args |
Example
Rearranged from A Guide to Function Composition in Ruby.
# a.)
proc = proc { return }
lambda = -> { return }
def call_proc_return
proc.call
"This will not be reached"
end
def call_lambda_return
lambda.call
"This will be reached"
end
call_proc_return # prints nil
call_lambda_return # prints "This will be reached"# b.)
proc = proc { |x, y| "#{x} and #{y}" }
lambda = ->(x, y) { "#{x} and #{y}" }
proc.(1, 2, 3) # prints "1 and 2"
lambda.(1, 2, 3) # ArgumentError (wrong number of arguments (given 3, expected 2))# c.)
proc = proc { |x, y| "#{x} and #{y}" }
lambda = ->(x, y) { "#{x} and #{y}" }
# note: some args below are a set of array,
# which is only ONE arg
proc.(1) # prints "1 and "
proc.([1, 2, 3]) # prints "1 and 2"
lambda.([1, 2, 3]) # ArgumentError (wrong number of arguments (given 1, expected 2))References
-
A Guide to Function Composition in Ruby by Paul Mucur
-
Closure (computer programming) on Wikipedia
-
Proc by ruby-doc.org
-
Procedure objects by ruby-doc.org
-
程式區塊與 Proc by openhome.cc
-
使用 Lambda by openhome.cc