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.