Can Procs or Lambdas receive blocks?

I’m trying this simple idea:

l = lambda { yield + 1 }
l.call { 2 } # I was expecting 3

Expecting the result to be 3, but I get LocalJumpError: no block given (yield).

So I can’t pass a block ({ 2 } in the example) to a lambda in the same way I would do with a method.

The same example with methods would be:

def m
  yield + 1
end
m {2} # 3

What I’m doing for now is to make my lamda to receive a callback:

l = lambda{|defer| defer.call + 1 }
l.call(lambda{ 2 }) # 3

But it would have been so nice to use the block instead.

So. Does anybody if this is all there is to say about this, or it is actually possible and I’m making a mistake?

I’m really interested in what a competent Ruby programmer would suggest but in the mean while I’d do something like this:

l = ->(&e){e.call("hello")}
l.call{|e| puts e}
1 Like

Thank you!

I was assuming Procs definitions where not able to use the & for the last parameter.

I’m happy with that solution. What I wanted was a way to pass a block to a Proc on call, and that allows me to do that.

Note aside: It is not easy (at least for me) documentation about this feature. Just found in the book “Programming Ruby 1.9 & 2.0” in Chapter 22.13 “Blocks, Closures, and Proc Objects”.

The thing to keep in mind with blocks…

You are just surrendering data to a block of executable code.

There is no rule in Ruby that states that you have to use blocks to yield data to, you can just as easily pass a lambda and have the same result.

l = ->(e){puts e}

def get_each(f)
  f.call(1)
  f.call(2)
  f.call(3)
end

get_each l

Or if you prefer:

get_each ->(e){puts e}

Sure. That is kind of what I’ve been doing. Check my example with the “defer” variable:

l = lambda{|defer| defer.call + 1 }
l.call(lambda{ 2 }) # 3

The reason behind is hinted by the variable name “defer”. In your example, what I wanted to do was to defer the calculation of 1, 2 and 3 until f is called. So the code would be:

l = ->(deferred_e){puts deferred_e.call}

def get_each(f)
  f.call(lambda{1})
  f.call(lambda{2})
  f.call(lambda{3})
end

get_each l

The alternative I found nicer using the & as you suggested first is:

l = ->(&deferred_e){puts deferred_e.call}

def get_each(f)
  f.call {1}
  f.call {2}
  f.call {3}
end

get_each l