You cannot yield
from a lambda
directly to a nonexplicit block passed to it as you are doing now (See comments below for source provided by @cremno showing that yield
may only be used in method and singleton class definitions)
Source Extraction:
if ((type != ISEQ_TYPE_METHOD && type != ISEQ_TYPE_CLASS) || block == 0) {
rb_vm_localjump_error("no block given (yield)", Qnil, 0);
}
Primary Solution:
You could do this with an explicit block like so
f = lambda do |data,&block|
data.select do |m|
block.call(m)
end.map do |m|
[m, block.call(m)]
end
end
d = ["string",1,2,3,4,"string2"]
f.call(d) { |n| n.is_a?(String) }
#=>[["string", true], ["string2", true]]
Secondary Solution:
However you can also yield
inside the lambda
if the block is passed to the method instead e.g.
def some_method(data)
#extended syntax for readability but works fine as
#f = lambda{|data,&block| data.select{|m| block.call(m) }.map { |m| [m, block.call(m)]}}
f = lambda do |data|
data.select do |m|
yield(m)
end.map do |m|
[m, yield(m)]
end
end
f.call(data)
end
some_method(["string",1,2,3,4,"string2"]) { |s| s.is_a?(String) }
#=> [["string", true], ["string2", true]]
Tertiary Soultion: (A spawn of the secondary solution that more closely matches your question)
Define a secondary method
def some_method(some_data)
x = filter(some_data) {|m| m.is_a?(String)}
y = filter(some_data) {|m| m.is_a?(Fixnum)}
[x, y]
end
def filter(data)
data.select do |m|
yield(m)
end.map do |m|
[m, yield(m)]
end
end
some_method(["string",1,2,3,4,"string2"])
#=>[
[["string", true], ["string2", true]],
[[1, true], [2, true], [3, true], [4, true]]
]
Quaternary Solution:
There is technically a fourth option and I am posting it just for your sake because it represents your original code as closely as possible. It is by far the strangest pattern (almost as strange as the word quaternary) of the 4 but I like to be thorough:
def some_method(some_data)
f = lambda{|data| data.select{|m| yield(m) }.map { |m| [m, yield(m)]}}
if block_given?
f.call(some_data)
else
x = some_method(some_data) {|m| m.is_a?(String)}
y = some_method(some_data) {|m| m.is_a?(Fixnum)}
[x,y]
end
end
some_method(["string",1,2,3,4,"string2"])
#=>[
[["string", true], ["string2", true]],
[[1, true], [2, true], [3, true], [4, true]]
]