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

T

timr

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)} }
 
S

Skye Shaw!@#$

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
 
S

Skye Shaw!@#$

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 }
 
B

botp

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

try,

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

rare code, rare solution :)

kind regards -botp
 
T

timr

Thanks skye and botp. Both interesting solutions.

I also found this:
http://www.skorks.com/2010/05/ruby-procs-and-lambdas-and-the-difference-between-them/
"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.
 
W

w_a_x_man

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)} }


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)
}
 
T

timr

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)

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
 
B

botp

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top