Proc and lambda objects store callable behavior in variables.

callable object A callable object can be assigned to a variable and later invoked with `call`.

Proc Lambda

base
proc_lambda.rb
Replay: real traced execution (multi-file project)
base = 4

doubler = Proc.new do |value|
  value * 2
end

labeler = lambda do |value|
  "value=#{value}"
end

result = doubler.call(base)
label = labeler.call(result)

puts "base=#{base}"
puts label
base = 2

doubler = Proc.new do |value|
  value * 2
end

labeler = lambda do |value|
  "value=#{value}"
end

result = doubler.call(base)
label = labeler.call(result)

puts "base=#{base}"
puts label
base = 8

doubler = Proc.new do |value|
  value * 2
end

labeler = lambda do |value|
  "value=#{value}"
end

result = doubler.call(base)
label = labeler.call(result)

puts "base=#{base}"
puts label
  1. base ← 4, doubler ← ⟨Proc A /tmp/execution/⟨tmp B⟩.rb:33⟩, labeler ← ⟨Proc C /tmp/execution/⟨tmp B⟩.rb:48 (lambda)⟩

    1base→ 4 = 4  #@base=2, 823doubler→ ⟨Proc A /tmp/execution/⟨tmp B⟩.rb:33⟩ = Proc.new do |value|4  value * 25end67labeler→ ⟨Proc C /tmp/execution/⟨tmp B⟩.rb:48 (lambda)⟩ = lambda do |value|8  "value=#{value}"9end1011result = doubler.call(base)812label = labeler.call(result)
  2. do |value|

    3doubler = Proc.new do |value4|4  value * 25end
  3. result ← 8

    11result→ 8 = doubler.call(base)812label = labeler.call(result)value=8
  4. do |value|

    7labeler = lambda do |value8|8  "value=#{value}"9end
  5. label ← value=8

    11result = doubler.call(base)12label→ value=8 = labeler.call(result)value=81314puts "base=#{base4}"15puts labelvalue=8
    outputbase=4
    value=8
  1. base ← 2, doubler ← ⟨Proc A /tmp/execution/⟨tmp B⟩.rb:33⟩, labeler ← ⟨Proc C /tmp/execution/⟨tmp B⟩.rb:48 (lambda)⟩

    1base→ 2 = 223doubler→ ⟨Proc A /tmp/execution/⟨tmp B⟩.rb:33⟩ = Proc.new do |value|4  value * 25end67labeler→ ⟨Proc C /tmp/execution/⟨tmp B⟩.rb:48 (lambda)⟩ = lambda do |value|8  "value=#{value}"9end1011result = doubler.call(base)412label = labeler.call(result)
  2. do |value|

    3doubler = Proc.new do |value2|4  value * 25end
  3. result ← 4

    11result→ 4 = doubler.call(base)412label = labeler.call(result)value=4
  4. do |value|

    7labeler = lambda do |value4|8  "value=#{value}"9end
  5. label ← value=4

    11result = doubler.call(base)12label→ value=4 = labeler.call(result)value=41314puts "base=#{base2}"15puts labelvalue=4
    outputbase=2
    value=4
  1. base ← 8, doubler ← ⟨Proc A /tmp/execution/⟨tmp B⟩.rb:33⟩, labeler ← ⟨Proc C /tmp/execution/⟨tmp B⟩.rb:48 (lambda)⟩

    1base→ 8 = 823doubler→ ⟨Proc A /tmp/execution/⟨tmp B⟩.rb:33⟩ = Proc.new do |value|4  value * 25end67labeler→ ⟨Proc C /tmp/execution/⟨tmp B⟩.rb:48 (lambda)⟩ = lambda do |value|8  "value=#{value}"9end1011result = doubler.call(base)1612label = labeler.call(result)
  2. do |value|

    3doubler = Proc.new do |value8|4  value * 25end
  3. result ← 16

    11result→ 16 = doubler.call(base)1612label = labeler.call(result)value=16
  4. do |value|

    7labeler = lambda do |value16|8  "value=#{value}"9end
  5. label ← value=16

    11result = doubler.call(base)12label→ value=16 = labeler.call(result)value=161314puts "base=#{base8}"15puts labelvalue=16
    outputbase=8
    value=16

Follow the Calls

  1. base starts as 4.
  2. doubler.call(base) returns 8.
  3. labeler.call(8) builds the text value=8.
  4. The program prints base=4 and value=8. | call | input | result | | --- | --- | --- | | doubler | 4 | 8 | | labeler | 8 | value=8 |

Exercise: proc_lambda.rb

Reproduce base=4 and value=8, then use the pinned base variants to predict value=4 and value=16.