Is it possible to break a loop from within an internal lambda function?

This code works because ‘exit’ within the lambda within the block
stops the loop. However, I don’t want to stop the program. I need to
use break rather than exit. But break won’t work within that lambda–
the loop doesn’t stop. I can of course reorganize the statement so
that it isn’t a terse one-liner, and get it to work. But I would like
to be able to break the loop from within that lambda function if it is
possible. Somehow, I guess I need to make that break have a binding
to the method. Any ideas?!?

def solve_by_iter
counter = 1
loop do
yield counter
counter += 1
end
end
solve_by_iter { |test| lambda{puts test; exit}.call if (1…6).all?{|
num| test%num == (num-1)} }
#I want to use: solve_by_iter { |test| lambda{puts test; break}.call
if (1…6).all?{|num| test%num == (num-1)} }

On Nov 14, 12:54am, timr [email protected] wrote:

This code works because ‘exit’ within the lambda within the block
stops the loop. However, I don’t want to stop the program. I need to
use break rather than exit.

#I want to use: solve_by_iter { |test| lambda{puts test; break}.call
if (1…6).all?{|num| test%num == (num-1)} }

This seems like an odd code arrangement.

What’s wrong with returning a boolean value from the inner lambda and
breaking in the block?

solve_by_iter { |test| break if lambda{puts test; false}.call }

-Skye

On Nov 14, 1:18am, “Skye Shaw!@#$” [email protected] wrote:

On Nov 14, 12:54am, timr [email protected] wrote:

#I want to use: solve_by_iter { |test| lambda{puts test; break}.call
if (1…6).all?{|num| test%num == (num-1)} }

What’s wrong with returning a boolean value from the inner lambda and
breaking in the block?

solve_by_iter { |test| break if lambda{puts test; false}.call }

Though if you really, really -really, want to kill the call stack from
an arbitrary depth you could try (gulp):

def solve_by_iter
counter = 1
catch :break do
loop do
yield counter
counter += 1
end
end
end

solve_by_iter { |test| lambda{p test;throw :break}.call }

On Sun, Nov 14, 2010 at 4:55 PM, timr [email protected] wrote:

solve_by_iter { |test| lambda{puts test; exit}.call if (1…6).all?{|
num| test%num == (num-1)} }

try,

solve_by_iter { |test| break(lambda{puts test}.call) if
(1…6).all?{|num| test%num == (num-1)} }

rare code, rare solution :slight_smile:

kind regards -botp

Thanks skye and botp. Both interesting solutions.

I also found this:

“We get a LocalJumpError, what happened? Well, the break keyword is
used to break out of iteration, and we didn’t have an iterator around
our proc, so we couldn’t break out of anything, so Ruby tries to
punish us with an error. If we put an iterator around our proc,
everything would be fine:”

It gave me a better understanding of subtleties of lambdas and Procs.
Though, it looks like to make it work an iterator has to wrap the
calling of the proc more directly. I’ll have to play with that more to
understand why. For the time being, I think break(lambda{}.call) is
the simplest solution.

On Nov 14, 4:46am, w_a_x_man [email protected] wrote:

This code works because ‘exit’ within the lambda within the block
loop do
if (1…6).all?{|num| test % num == num - 1 }
puts test
break
end

}

solve_by_iter{|test|
(1…6).all?{|num| test%num == num-1} and (puts test; break)

That is also a clever solution. It uses ‘and’ for its ability control
whether a second statement should be evaluated rather than its boolean
sense. And I hadn’t seen parentheses used to create multiline
statements like this before. That is the only reason I had been using
lambda before–to get a block of code with more than one line to be
executed as a single unit.

Similarly, break() is useful as previously suggested. The break() also
removes the need for a lambda statement. Combining solutions, and
using the if statement rather than ‘and’ which in my mind is slightly
easier to read, how about this (w/ slight refactoring of variable
names):

def solve_by_iter
counter = 1
loop do
yield(counter)
counter+=1
end
end

solve_by_iter{|numer| (puts numer; break) if (1…6).all?{|denom| numer
%denom == denom-1}}

Thanks guys, I learned a lot from your responses to this post.
Tim

solve_by_iter{|numer| (puts numer; break) if (1…6).all?{|denom| numer
%denom == denom-1}}

in short, you can simply do

puts (1…1/0.0).find{|num| (1…6).all?{|denom| num % denom == denom - 1}
}
59

kind regards -botp

On Nov 14, 2:54am, timr [email protected] wrote:

counter = 1
loop do
yield counter
counter += 1
end
end
solve_by_iter { |test| lambda{puts test; exit}.call if (1…6).all?{|
num| test%num == (num-1)} }
#I want to use: solve_by_iter { |test| lambda{puts test; break}.call
if (1…6).all?{|num| test%num == (num-1)} }

solve_by_iter{|test|
if (1…6).all?{|num| test % num == num - 1 }
puts test
break
end
}

solve_by_iter{|test|
(1…6).all?{|num| test%num == num-1} and (puts test; break)
}