Why can't I pass two blocks to a method?

T

Tim L

Hi:

This is a newbie question.

In the code below I'm developing methods to generate various mathematical
sequences.

I'm really happy that I can pass a block of code to define the rule to
generate the next number in a sequence, e.g. the Fibonacci sequence. But I
also need a rule to say when to stop, and I was wondering whether I could
also pass that as a block. I can't see how, although I can define it as a
Proc.

Tim L

EPS = 10 ** -12 # i.e. a very small number to test for convergence

#uses (1) push, last array methods
# uses negative indices to get most recent numbers put in list

#Fibonacci
seq = [1, 1]
9.times do |i|
seq.push(seq[-1] + seq[-2])
end

puts seq.join(", ")

#Root N
n = 1.5 # make sure a float
seq = [0,1]

while seq[-1] != seq[-2]
seq.push(seq[-1] + (n - seq[-1]**2 ) / (seq[-1] * 2) )
end

puts seq.last
puts seq.length
puts n**(0.5)

seq = [0,1]
while (seq[-1] - seq[-2]).abs >EPS
seq.push(seq[-1] + (n - seq[-1]**2 ) / (seq[-1] * 2) )
end

puts seq.last
puts seq.length
puts n**(0.5)

fibo = Proc.new do |arr| #capital letter in Proc matters!
arr.push(arr[-1] + arr[-2])
end

seq = [1,1]
9.times do
fibo.call(seq)
end

puts seq.join(", ")


def buildSeq(arr, &pr) # '&' indicates that the argument here is going to be
a block

9.times do
pr.call(arr)
end
end

seq = [1,1]

buildSeq(seq) {|arr| arr.push(arr[-1] + arr[-2]) }

puts seq.join(", ")

myTest = Proc.new do |arr|
(arr[-1] - arr[-2]).abs > EPS
end

def buildSeqTest(arr, test, &pr) # test is a proc. Why can't I pass two
blocks to a method?

while test.call(arr)
pr.call(arr)
end
end
n = 17.0
seq = [1,2]

buildSeqTest(seq, myTest) {|arr| arr.push(arr[-1] + (n - arr[-1]**2 ) /
(arr[-1] * 2) )}

puts seq.last
 
B

baumanj

Syntactically, there's no way to pass more than one block that can be
yielded to, but you can achieve essentially the same effect by creating
Proc objects and passing them as regular parameters. Then, instead of
yielding, just use the call (or []) method.
 
T

Trans

In some respects it of course would be nice if we could. A do-with-end
syntax like if-else-end would work.

doubleup(x,y,z) do
#... 1st proc
with
# .. 2nd proc
end

I don't know how that would translate to { ... } notation though. But
anyway, Matz has never seems keen on the idea. I think the idea is that
blocks are sort of like XML elemet bodies --there's just one. Which,
btw, makes we sometimes wish we could have string blocks somehow; the
block notion being so nice and all.

To double block now, what you need to do is allow the first emthod just
to build up an object holding the initil proc.

doublup( ... ){ ... }.with{ ... }

For example:

def doubleup(&blk)
Functor.new { |op, *args|
case op
when :with
blk.call + args.last.call
end
}
end

duobleup{ "Hello" }.with{ "World!" }
=> HelloWorld!

Unfortuately the stable version of Ruby doesn't yet support block
passing via blocks. Bu tyou can get the block via the argument list as
shown. Note that Fucntor is part of Facets library --previous versions
of Functor weren't allowing the block through so here's updated code
for that:

class Functor < BasicObject

def initialize(*obj, &func)
@obj = obj
@func = func
end

def method_missing(op, *args, &blk)
if block_given?
@func.call(op, *(@obj + args + [blk]))
else
@func.call(op, *(@obj + args))
end
end

def instance_objects
return obj
end

end

T.
 

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

No members online now.

Forum statistics

Threads
473,983
Messages
2,570,187
Members
46,747
Latest member
jojoBizaroo

Latest Threads

Top