4

Given,

  def wrapper &block
    (1..5).inject yield
  end

  proc = Proc.new {|sum, n| sum + n }

Why can't I do this call?

  wrapper &proc
  => NoMethodError: undefined method `+' for nil:NilClass

When looking inside, I see that inject has not been able to assign the memo or the obj, as rewriting the proc to be proc = Proc.new {|memo, obj| puts memo ; puts obj } returns 10 iterations of nothing. I also noted that (1..5).inject takes only one argument, what it passes in as the initial memo, and that technically it doesn't the block as a real argument.

Alex Moore-Niemi
  • 2,913
  • 2
  • 24
  • 22
  • possible duplicate of [Understanding the behaviour of inject used with a lambda in Ruby](http://stackoverflow.com/questions/102165/understanding-the-behaviour-of-inject-used-with-a-lambda-in-ruby) – infused Jul 11 '14 at 02:09

2 Answers2

8

The way to do it is

def wrapper &block
  ( 1..5 ).reduce &block
end

p = proc { |a, b| a + b }

wrapper &p
#=> 15

But in your question, you interestingly attempted to use yield. When you use yield, you don't need to explicitly mention the &block parameter – a method cannot refuse a block, which is always callable by yield inside the method. However, yield expects arguments. The way to use yield to achieve your goal is:

def wrapper_2
  ( 1..5 ).reduce { |accumulator, input| yield accumulator, input }
end

This formulation is still a bit awkward. It turns out that there is a secret way to obtain the block inside a method even if you do not specify the &block parameter, and that is by using unadorned Proc.new inside the method:

def wrapper_3
  ( 1..5 ).reduce &Proc.new
end
Boris Stitnicky
  • 12,444
  • 5
  • 57
  • 74
0

Thanks for pointing out the related question! My googling and the site-search mechanism didn't point me there before. It helped me see I'd just made a dumb syntax error earlier (I tried a call of (1..5).inject([]) proc) that made me misunderstand what I was seeing. So what I needed was in fact:

def wrapper proc
  (1..5).inject 0, proc
end
Alex Moore-Niemi
  • 2,913
  • 2
  • 24
  • 22
  • Did you test it? When I try your `wrapper` by calling `wrapper &proc` as you specified in your question, it gives me an error. – Boris Stitnicky Jul 11 '14 at 02:36
  • So I also changed the call to be just wrapper proc, and that works fine. The next step I've come to which has also stumped me is this: `summer = Proc.new {|sum, n| sum + n}`; `rap = Proc.new {|proc| (1..5).inject 0, proc}` ; `curried = rap.curry` ; `curried[summer]` results in: `TypeError: # is not a symbol`. :c – Alex Moore-Niemi Jul 11 '14 at 02:52
  • Another stupid mistake! I needed this: `rap = Proc.new {|proc| (1..5).inject 0, &proc}` and now, voila, it works. – Alex Moore-Niemi Jul 11 '14 at 02:56
  • This is where I ended up, Boris: https://github.com/mooreniemi/experiments/blob/master/curried_summer.rb – Alex Moore-Niemi Jul 11 '14 at 03:39
  • 1
    Hm, and when defining a Proc, you can just say `proc { |a, b| a + b }` instead of `Proc.new { |a, b| a + b }`. – Boris Stitnicky Jul 12 '14 at 02:39