Continuation usage

P

Patrick Roemer

Once again I've been trying to get a grip on continuations, however, I'm
quite unsure whether I've really got it this time. Could anybody please
take a look at the example 'server' below. It seems to work when called
from irb, but I'm unclear on how to test such a beast programmatically,
so I suspect I somehow must have got it wrong again.

TIA,
Patrick

class ContServer
def initialize()
@blocks={} # named services
@mains={} # top-level continuations by session id
@conts={} # service continuations by session id
end

def add(name,&block)
@blocks[name]=block
end

def service(id,name='',inp='')
callcc do |cc|
@mains[id]=cc # remember top-level continuation
if(@conts.key?(id)) # already in session?
@conts[id].call(inp) # return to service continuation
else
ret=@blocks[name].call(id,self) # enter new session
@conts.delete(id) # finish session
ret
end
end
end

def io(id,out)
callcc do |cc|
@conts[id]=cc # remember service continuation
@mains[id].call(out) # return to top-level continuation
end
end

def ContServer::init
cs=ContServer.new
cs.add('guess') do |id,server|
target=rand(100)
inp=server.io(id,"Please enter a number between 1 and 100.").to_i
round=1
while(inp!=target)
inp=server.io(id,(inp < target ? "Higher" : "Lower")).to_i
round += 1
end
"You found it in #{round} rounds."
end
cs
end
end
 
C

Chad Fowler

Once again I've been trying to get a grip on continuations, however,
I'm
quite unsure whether I've really got it this time. Could anybody please
take a look at the example 'server' below. It seems to work when called
from irb, but I'm unclear on how to test such a beast programmatically,
so I suspect I somehow must have got it wrong again.

TIA,
Patrick
--snip--code

How are you calling it from IRB? It didn't work for me, and before I
spent too much time trying to figure out why, I thought I'd ask this
first.

Chad
 
P

Patrick Roemer

Chad said:
How are you calling it from IRB? It didn't work for me, and before I
spent too much time trying to figure out why, I thought I'd ask this
first.

Thanks for your reply. I have to admit that 'calling from irb' is not a
very detailed description. ;) I meant something like this:

irb(main):001:0> require 'conttest.rb'
=> true
irb(main):002:0> cs=ContServer.init
=> #<ContServer:0x2812560 @conts={},
@mains={}, @blocks={"guess"=>#<Proc:0x02812548@./conttest.rb:34>}>
irb(main):003:0> cs.service(1,'guess',50) # (last arg ignored)
=> "Please enter a number between 1 and 100."
irb(main):004:0> cs.service(1,'guess',50) # (middle arg ignored)
=> "Lower"
irb(main):005:0> cs.service(1,'guess',25) # (middle arg ignored)
=> "You found it in 2 rounds."
irb(main):006:0> cs.service(1,'guess',25) # (last arg ignored)
=> "Please enter a number between 1 and 100."
irb(main):007:0> cs.service(1,'guess',50) # (middle arg ignored)
=> "Higher"

....and so on. This also seems to work with multiple 'services' and
multiple 'users' (i.e. IDs) with interleaved access.

Please try to ignore the crappy arg handling (and also the off-by-one
error for the random expectation). I'm just trying to figure out how a
continuation-based web server is supposed to work. For me this was the
'simplest thing that could possibly emulate this'. Perhaps I am totally
off the track, but if so, I'd really like to know why.

Regards,
Patrick
 
K

Kristof Bastiaensen

Hi,

Once again I've been trying to get a grip on continuations, however, I'm
quite unsure whether I've really got it this time. Could anybody please
take a look at the example 'server' below. It seems to work when called
from irb, but I'm unclear on how to test such a beast programmatically,
so I suspect I somehow must have got it wrong again.

This looks very solid to me. Maybe you could make every
Service a subclass of ContSession, and every session an
instance of that session. It would look something like this:

class ContSession
def start(*args)
callcc do |cc|
@main = cc
session(*args)
end
end

def service(arg)
callcc do |cc|
@main = cc
@cont.call(arg)
end
end

def io(out)
callcc do |cc|
@cont = cc
@main.call(out)
end
end
private :io
end

class Guess < ContSession
def session
target = rand(100)
inp = io("Please enter a number between 1 and 100.").to_i
round = 1
while(inp != target)
inp = io(inp < target ? "Higher" : "Lower").to_i
round += 1
end
"You found it in #{round} rounds."
end
private :session
end

irb(main):002:0> g = Guess.new
#<Guess:0x402a7484>
irb(main):003:0> g.start
"Please enter a number between 1 and 100."
irb(main):004:0> g.service(50)
"Lower"
irb(main):005:0> g.service(25)
"Higher"
irb(main):006:0> g.service(37)
"Lower"
irb(main):007:0> g.service(31)
"Higher"
irb(main):008:0> g.service(34)
"You found it in 5 rounds."
 
K

Kristof Bastiaensen

Hi,

Once again I've been trying to get a grip on continuations, however, I'm
quite unsure whether I've really got it this time. Could anybody please
take a look at the example 'server' below. It seems to work when called
from irb, but I'm unclear on how to test such a beast programmatically,
so I suspect I somehow must have got it wrong again.

It looks very solid to me. Maybe you could make every Service a
subclass of ContSession, and every session an instance of that Session.
It would look something like this:

class ContSession
def start(*args)
callcc do |cc|
@main = cc
session(*args)
end
end

def service(arg)
callcc do |cc|
@main = cc
@cont.call(arg)
end
end

def io(out)
callcc do |cc|
@cont = cc
@main.call(out)
end
end
private :io
end

class Guess < ContSession
def session
target = rand(100)
inp = io("Please enter a number between 1 and 100.").to_i
round = 1
while(inp != target)
inp = io(inp < target ? "Higher" : "Lower").to_i
round += 1
end
"You found it in #{round} rounds."
end
private :session
end

irb(main):002:0> g = Guess.new
#<Guess:0x402a7484>
irb(main):003:0> g.start
"Please enter a number between 1 and 100."
irb(main):004:0> g.service(50)
"Higher"
irb(main):005:0> g.service(75)
"Higher"
irb(main):006:0> g.service(81)
"Higher"
irb(main):007:0> g.service(90)
"Higher"
irb(main):008:0> g.service(95)
"Lower"
irb(main):009:0> g.service(93)
"Lower"
irb(main):010:0> g.service(91)
"You found it in 7 rounds."
irb(main):011:0>
 
K

Kaspar Schiess

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Patrick Roemer wrote:

| Once again I've been trying to get a grip on continuations, however, I'm

Your code looks solid and as though you have been trough with the
concept. Might I suggest the source code of Borges for further reading
on this subject ? ;)

(I guess you know Seaside and/or other Continuation based web
programming frameworks, there seems to be a bit of talk about that lately).

kaspar - code philosopher

- -- stolen off the net --
So much for taking the world by storm. I guess I'll have to take it by
siege.
-- Jay J. P. Scott
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (MingW32)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFAenD4Fifl4CA0ImQRAm8pAJsH4XLFKxKAkZ5IHNZk41XthXP79wCfZAjc
IqU0lwab1IAA4cwdsFtINC8=
=cgpK
-----END PGP SIGNATURE-----
 
P

Patrick Roemer

Kristof said:
It looks very solid to me.

In the meantime I've found out that the problem was not in the code I
posted, but in my test. :/

Your version looks really nice. I think it could fit nicely with the
other continuation examples in the Ruby FAQ. Thanks.

Regards,
Patrick
 
P

Patrick Roemer

Kaspar said:
Your code looks solid and as though you have been trough with the
concept. Might I suggest the source code of Borges for further reading
on this subject ? ;)

Good idea, I hadn't discovered Borges yet.
(I guess you know Seaside and/or other Continuation based web
programming frameworks, there seems to be a bit of talk about that lately).

I've found continuations in Cocoon's flow script (i.e. in Cocoon's
Javascript/Rhino extension), but before using it, I wanted to get a grip
on the basic concept and I felt more comfortable experimenting with it
in Ruby rather than Javascript or Scheme. Now that I seem to have got
it, I'll have a look at Borges to see it in action. Thanks for the hint.

Regards,
Patrick
 
C

Chad Fowler

I've found continuations in Cocoon's flow script (i.e. in Cocoon's
Javascript/Rhino extension), but before using it, I wanted to get a
grip
on the basic concept and I felt more comfortable experimenting with it
in Ruby rather than Javascript or Scheme. Now that I seem to have got
it, I'll have a look at Borges to see it in action. Thanks for the
hint.

I've also written a tiny bit of code to attempt to educate myself and
others on how Seaside-like frameworks work. I plan to eventually
implement all of the "tricks" that Seaside employs in as little code as
possible (with the goal being clarity--not brevity). Right now I just
have the first trick implemented. The code is really stupid, but
that's beside the point. :)

http://chadfowler.com/lazyseaside/pm_seaside.html

Ignore the "seasidehints.out" and "wrap_methods" stuff. That's
unrelated and part of another idea I was exploring
(http://chadfowler.com/index.cgi/Computing/Programming/Ruby/
TypeWatching.rdoc,v).


Chad
 
K

Kaspar Schiess

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

| I've found continuations in Cocoon's flow script (i.e. in Cocoon's
| Javascript/Rhino extension), but before using it, I wanted to get a grip
| on the basic concept and I felt more comfortable experimenting with it
| in Ruby rather than Javascript or Scheme. Now that I seem to have got
| it, I'll have a look at Borges to see it in action. Thanks for the hint.

Have a look at Borges then, it does what you want and ten times more: It
rocks ! (Having come the same way from Cocoon... )


kaspar - code philosopher

- -- stolen off the net --
"It takes real courage to be a Macintosh user; it takes real conviction;
~ not unlike being a Christian in the days of the Romans."
~ - Guy Kawasaki, Chief Evangelist for Apple Computer - from "Hotseat"
~ interview with John McChesney (3/28/97)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (MingW32)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFAeoLCFifl4CA0ImQRAiBDAKCLe4eZRf+/8DRCbN+9U25Z8TU6jgCgtjcK
gJypeQXuVBj1rhYW0sbKxzI=
=BR3H
-----END PGP SIGNATURE-----
 
K

Kristof Bastiaensen

Your version looks really nice. I think it could fit nicely with the
other continuation examples in the Ruby FAQ. Thanks.

Thanks!
Maybe you are interested in the following code (if it
doesn't exist already). In implements a kind of goto:

class Mark
def initialize
@cc = callcc { |cc| cc }
end
def goto #should be called teleport
@cc.call(@cc)
end
end

#-- (the example is quite stupid, but just to show the concept)

irb(main):006:0> begin
irb(main):007:1* a = Mark.new
irb(main):008:1> a.goto if gets.chomp != "stop"
irb(main):009:1> end
Hi, there
Everything ok!
stop
nil
irb(main):010:0>

#----
 

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,968
Messages
2,570,149
Members
46,695
Latest member
StanleyDri

Latest Threads

Top