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

Discussion in 'Ruby' started by timr, Nov 14, 2010.

  1. timr

    timr Guest

    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)} }
     
    timr, Nov 14, 2010
    #1
    1. Advertising

  2. On Nov 14, 12:54 am, timr <> 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
     
    Skye Shaw!@#$, Nov 14, 2010
    #2
    1. Advertising

  3. On Nov 14, 1:18 am, "Skye Shaw!@#$" <> wrote:
    > On Nov 14, 12:54 am, timr <> 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 }
     
    Skye Shaw!@#$, Nov 14, 2010
    #3
  4. timr

    botp Guest

    On Sun, Nov 14, 2010 at 4:55 PM, timr <> wrote:
    > 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
     
    botp, Nov 14, 2010
    #4
  5. timr

    timr Guest

    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.
     
    timr, Nov 14, 2010
    #5
  6. timr

    w_a_x_man Guest

    On Nov 14, 2:54 am, timr <> 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. 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)
    }
     
    w_a_x_man, Nov 14, 2010
    #6
  7. timr

    timr Guest

    On Nov 14, 4:46 am, w_a_x_man <> wrote:
    > On Nov 14, 2:54 am, timr <> 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. 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)
    >


    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
     
    timr, Nov 15, 2010
    #7
  8. timr

    botp Guest

    > 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
     
    botp, Nov 15, 2010
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Roman Suzi
    Replies:
    13
    Views:
    627
    Bengt Richter
    Jan 7, 2005
  2. Replies:
    12
    Views:
    1,007
  3. Steve Dogers

    lambda vs non-lambda proc

    Steve Dogers, Mar 30, 2009, in forum: Ruby
    Replies:
    1
    Views:
    202
    Sean O'Halpin
    Mar 30, 2009
  4. Isaac Won
    Replies:
    9
    Views:
    444
    Ulrich Eckhardt
    Mar 4, 2013
  5. Haochen Xie
    Replies:
    4
    Views:
    261
    Haochen Xie
    Mar 17, 2013
Loading...

Share This Page