Here's my entry for the 'writing BASIC in Ruby' competition:
$lines = {}
$running = false
$tron = false
def line(n,&blk)
callcc { |$lines[n]| }
puts "Line #{n}" if $tron and $running
yield if $running
end
def goto n
$lines[n].call
end
def run
unless $running
$running = true
$lines.sort[0][1].call
$end
end
line(100) { puts "Hello World" }
line(110) { $i = 0 }
line(120) { if $i > 10 then goto 160 end }
line(130) { puts "Current $i: %d" % [$i] }
line(140) { $i = $i + 1 }
line(150) { goto 120 }
line(160) { puts "Done!" }
line(170) { puts "Stopping now" }
# $tron = true
run
One thing worth mentioning about continuations is that as far as I can tell,
Continuation#call NEVER RETURNS. You are not pushing the current execution
state onto a stack like Method#call or Proc#call; you are simply replacing
the current execution context, like a longjmp in C. The current execution
thread is lot. In that case perhaps 'call' is not the ideal name for this
method.
The thing I am not sure of is what values of variables, if any, are bound up
in the continuation. Take the following example:
i = 0
here = nil
callcc {|here|}
puts i
i = i + 1
here.call unless i == 10 # here.call is just "goto here"
puts "Done!"
This is not recursive - as mentioned before, here.call just rewinds to the
point after the callcc.
Now, clearly the *value* of variable 'i' at callcc time is not included in
the continuation object 'here', because when I do 'here.call', the
subsequent 'puts i' shows 'i' with its new value.
I think what confuses me is the discussion on the Wiki about coming to a
crossroads, taking the left path, finding that you get bitten by a dog, and
then deciding that was a bad idea so you 'rewind back in time' to the
crossroads. But if you did this using a Ruby continuation, surely your leg
would still be bleeding?
preferred_path = "LEFT"
bleeding = false
crossroads = nil
callcc{ |crossroads| }
puts "At the crossroads"
puts bleeding ? "I am bleeding!" : "I am OK"
puts "I am going to go #{preferred_path}"
if preferred_path == "LEFT"
sleep 2
puts "Bitten by dog!"
bleeding = true
preferred_path = "RIGHT"
crossroads.call
else
sleep 2
puts "Hit by train!"
exit
end
Regards,
Brian.