From: Harry Ohlsen Date: 2003-07-09T17:40:40+09:00 Subject: Re: Possible use for a continuation? [Generating all factors of a given number] daz wrote: > Continuations might be more-than-required since you > suggest that when a condition arises, the game is up. Darn! I was hoping to finally get a chance to use one :-). > catch / throw may be what you need. > > N.B. I haven't done the job but just to show that > throw can be issued from anywhere ... > > def gen_value_single(n, r) > ret_ = [] > 0.upto(r) do |i| > ret_ << n ** i > throw :enough if ((false)) > end > ret_ > end > > def gen_values(arr) > all_done = false > catch :enough do > arr.each do |n, r| > p gen_value_single(n, r) > # > ### accumulate stuff > # > throw :enough if ((false)) > end > all_done = true > end # post-catch > return all_done > end > > gen_values( [[2,3], [3,2], [5,2], [7,1]] ) > > > And, because I don't know your condition, > I've entered false. What I was really trying to achieve, though, was to have a generic iterator that invoked a block that was passed to it, passing each factor as it was calculated, but for that block to be able to determine that it didn't want any more values. Alternatively, and I felt this would work more cleanly, I'd like a re-entrant generator that could simply be called multiple times, returning the next value each time. That way the caller doesn't need to communicate the fact that no more values are required, it simply wouldn't call the generator any more. This is where I thought a continuation might help. What I ended up with was this ... def Primes.each_factor(n, &block) prime_factors = factors(n) iterate_over_factors(1, prime_factors, &block) end def Primes.iterate_over_factors(start, factors, &block) first = factors[0] rest = factors[1 .. -1] factor = first[0] exponent = first[1] x = start (0 .. exponent).each do |i| if rest.length == 0 if !block.call(x) return false end else if !iterate_over_factors(x, rest, &block) break end end x *= factor end end which can be called like ... isGenerator = true Primes.each_factor(phi) do |factor| exponent = phi / factor if (i ** exponent).to_i == 1 isGenerator = false end isGenerator end The only problem with this is that you can't really "return" a value from a block (or, at least, I don't believe so), which makes the last line, which has to "return" true or false, so that the iterator knows whether to continue, isn't quite as obvious as I'd like. As I say, to me it would be much nicer if I could do something like ... factors = Primes.factors(phi) while (f = factors.next()) exponent = phi / factor if (i ** exponent).to_i == 1 return false end end return true because there's no need for the block to pass anything back to the generator (since the generator isn't actually passed the block). Anyway, I have something that works. But, I'd still be interested if someone feels like showing me how to achieve the equivalent generator that's being used in the last code snippet. Cheers, Harry O.