[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

nontinuations and throw / catch

treefrog

2/10/2005 11:31:00 AM

Hi folks,
I've been playing around with continuations a bit. What I'd like to be
abale to do is execute arbitary code sequences, suspend them, and then
resume them. All very well, and all what I can do using Continuation.

The problem is, that I want to be able to modify certain aspects of the
context while the code is suspended, and then have these picked up when
I resume. Consider the following code:

#callcc test

class Func
attr_reader :cont
def initialize
end

def do
@cont ? cont.call : do1
puts "after cont call"
end

def do1
puts 'A'
callcc { |cc| @cont=cc; throw :wait}
puts 'B'
@cont=nil
end


end

f=Func.new
(1..2).each do |i|
puts "Before do : i= #{i}"
catch :wait do
f.do
end
puts "After do : i= #{i}"


end



Now consider the output:

Before do : i= 1
A
After do : i= 1
Before do : i= 2
B
after cont call
After do : i= 1
Before do : i= 2
A
After do : i= 2

Basically, what is happening is that the continuation is the entire
programme context, and hence the loop variable i is overwritten.

This isn't quite what I am trying to achieve, which is to be able to
use a throw / catch mechanism in conjunction with the continuation to
be able to jump out of a function at arbitary points, and then return
to it later. What I really want is to be able to keep the contxt from
the catch downwards, so that I can keep the higher layers of the
context. In this case the desired output would be:

Before do : i= 1
A
After do : i= 1
Before do : i= 2
B
after cont call
After do : i= 2

Any ideas?

Best regards

Steve

PS (before anyone asks, I'm trying to put together a library for
discrete event simulation, and I'd like to be able to easily specify
arbitary breakpoints in functions, and then resume at them later, in
the knowledge that some (higher level) data may have changed.

5 Answers

Pit Capitain

2/10/2005 5:22:00 PM

0

Hi Steve,

you can find examples for continuations and coroutines in the archives of
ruby-talk. You can also look at the Generator class in the standard library. I
think for jumping back and forth you need two continuations instead of just one
continuation and a throw/catch. I can dig out some code samples if you need them.

Regards,
Pit


William Morgan

2/11/2005 6:36:00 PM

0

Excerpts from Pit Capitain's mail of 10 Feb 2005 (EST):
> you can find examples for continuations and coroutines in the archives
> of ruby-talk. You can also look at the Generator class in the standard
> library. I think for jumping back and forth you need two continuations
> instead of just one continuation and a throw/catch. I can dig out some
> code samples if you need them.

Pit is absolutely right: you don't need throw/catch, just two
continuations that you jump back and forth between.

Here's something I whipped up that lets you suspend and resume an
arbitrary function. For simplicity, it doesn't pass return values from
resume/suspend, but it wouldn't be too hard to modify it to do that.

(I also wrote about how generator.rb works at
http://www.all-thing.net/Ruby/iterators_generators_and_continuations_in..., which describes some of the idioms in using continuations.)

class Resumable
def initialize(&proc)
@inside = @outside = nil
@proc = proc
end

def call(*a)
raise "not in callable state" if @inside
if @outside = callcc { |c| c }
@proc.call self, *a
@outside.call if @outside
end
end

def resume
raise "not in a resumable state" unless @inside
@inside.call if @outside = callcc { |c| c }
end

def suspend
raise "not in a suspendable state" unless @outside
@outside.call if @inside = callcc { |c| c }
end
end

## example usage:

f = Resumable.new do |r|
puts "started!"
r.suspend
puts "in the middle"
r.suspend
puts "done!"
end

i = 0
puts "calling, i = #{i}"
f.call
puts "suspended, i = #{i}"

i += 1
puts "resuming, i = #{i}"
f.resume
puts "suspended, i = #{i}"

i += 1
puts "resuming, i = #{i}"
f.resume
puts "done, i = #{i}"

## end

HTH,

--
William <wmorgan-ruby-talk@masanjin.net>


William Morgan

2/11/2005 7:42:00 PM

0

Excerpts from William Morgan's mail of 11 Feb 2005 (EST):
> Here's something I whipped up that lets you suspend and resume an
> arbitrary function. For simplicity, it doesn't pass return values from
> resume/suspend, but it wouldn't be too hard to modify it to do that.

What the hey, here's a version that lets you pass values with suspend
and resume as well. It's not too much more complex.

class Resumable
def initialize(&proc)
@inside = nil
@outside = nil
@proc = proc
end

def callable?; @inside.nil?; end
def resumable?; !@inside.nil?; end
alias :done? :callable?

def call(*a)
raise "not in callable state" unless callable?
callcc do |c|
@outside = c
ret = @proc.call(self, *a)
@inside = nil
@outside.call(ret)
end
end

def resume(*a)
raise "not in a resumable state" unless resumable?
callcc do |c|
@outside = c
@inside.call(*a)
end
end

def suspend(*a)
raise "not in a suspendable state" unless @outside
callcc do |c|
@inside = c
@outside.call(*a)
end
end
end

## example

f = Resumable.new do |r, *args|
puts "a: started (args #{args.join(', ')})"
y = r.suspend "hello"
puts "a: said hello, got #{y}"
y = r.suspend "how\'s it going?"
puts "a: said how's it going, got #{y}"
y = r.suspend "goodbye!"
puts "a: done! said goodbye, got #{y}"
"see ya!"
end

puts "calling"
x = f.call "howdy"
puts "initial call: got #{x}"

i = 0
until f.done?
m = "message #{i}"
puts "b: resuming with #{m}"
x = f.resume m
puts "b: got #{x}"
i += 1
end

puts "done!"

## end

Output is:

calling
a: started (args howdy)
initial call: got hello
b: resuming with message 0
a: said hello, got message 0
b: got how's it going?
b: resuming with message 1
a: said how's it going, got message 1
b: got goodbye!
b: resuming with message 2
a: done! said goodbye, got message 2
b: got see ya!
done!

--
William <wmorgan-ruby-talk@masanjin.net>


gabriele renzi

2/11/2005 8:15:00 PM

0

William Morgan ha scritto:
> Excerpts from William Morgan's mail of 11 Feb 2005 (EST):
>
>>Here's something I whipped up that lets you suspend and resume an
>>arbitrary function. For simplicity, it doesn't pass return values from
>>resume/suspend, but it wouldn't be too hard to modify it to do that.
>
>
> What the hey, here's a version that lets you pass values with suspend
> and resume as well. It's not too much more complex.

I think you just reinvented coroutines :)

William Morgan

2/11/2005 10:06:00 PM

0

Excerpts from gabriele renzi's mail of 11 Feb 2005 (EST):
> >What the hey, here's a version that lets you pass values with suspend
> >and resume as well. It's not too much more complex.
>
> I think you just reinvented coroutines :)

Hey, just giving the people what they want. Not my fault it was invented
40 years ago. :)

--
William <wmorgan-ruby-talk@masanjin.net>