B
Blaine Buxton
Hello,
I was playing around with continuations by studying the generator code in
Hal Fulton's Ruby Way book. I decided to re-implement the code to test my
understanding. I decided to add the ability to backup the generator and
started to get "weird" results. I started to pass the intermediate values on
the stack and everything works. But, I would like to understand better why.
Can anyone help me? Thanks in advance! Here's my code with comments and
tests:
#playing with continuations
#inspired by Generator code in Hal Fulton's book
#I read it and then tried to recreate it to test my understanding
#I add the ability to "backup" the generator. I've added tests as well.
#
#I have to pass the locals on the stack to get it to work correctly? Why is
this?
#Is there something I am missing? I did use one less continuation, but it's
#just the continuation to continue the loop of the generator.
require 'test/unit'
class Generator
attr_accessor :currentContext, :contextHistory
def initialize()
self.currentContext=nil
self.reset
end
def next
callcc do |here|
self.currentContext=here
if self.contextHistory.empty?
generatorLoop
else
self.contextHistory.last.call
end
end
end
def backup
self.contextHistory.pop
end
def answer(value, *args)
callcc do |cont|
self.contextHistory.push(cont)
self.currentContext.call(value)
end
args
end
def reset()
self.contextHistory=[]
end
end
class Fibonacci < Generator
def generatorLoop
previous, current=0,1
loop do
#I pass the previous and current local variables as arguments just so
they are returned
#If I don't pass them, weird things happen which makes me think Ruby
#continuations only save part of the state or treats closures special
on the
#stack. The variables are local to the method and not the closure.
But, I still
#think the method's local state should be saved on the stack as well.
Am I missing
#something?
#works
previous, current = answer(current, previous, current)
#doesn't work, but I think it should, what am I missing?
#answer(current)
previous, current = current, previous + current
end
end
end
class TestFibonacci < Test::Unit::TestCase
attr_accessor :to_test
def setup
self.to_test=Fibonacci.new
end
def teardown
self.to_test=nil
end
def test_next
assert_equal(1, self.to_test.next)
assert_equal(1, self.to_test.next)
assert_equal(2, self.to_test.next)
assert_equal(3, self.to_test.next)
assert_equal(5, self.to_test.next)
assert_equal(8, self.to_test.next)
end
def test_back
(1..6).each { self.to_test.next }
assert_equal(13, self.to_test.next)
self.to_test.backup
assert_equal(13, self.to_test.next)
self.to_test.backup
self.to_test.backup
assert_equal(8, self.to_test.next)
assert_equal(13, self.to_test.next)
assert_equal(21, self.to_test.next)
end
end
--
Blaine Buxton, Mad Scientist In Training
My Amps: Smalltalk, Lisp, and Ruby
http://www.blainebuxton.com
_________________________________________________________________
Is your PC infected? Get a FREE online computer virus scan from McAfee®
Security. http://clinic.mcafee.com/clinic/ibuy/campaign.asp?cid=3963
I was playing around with continuations by studying the generator code in
Hal Fulton's Ruby Way book. I decided to re-implement the code to test my
understanding. I decided to add the ability to backup the generator and
started to get "weird" results. I started to pass the intermediate values on
the stack and everything works. But, I would like to understand better why.
Can anyone help me? Thanks in advance! Here's my code with comments and
tests:
#playing with continuations
#inspired by Generator code in Hal Fulton's book
#I read it and then tried to recreate it to test my understanding
#I add the ability to "backup" the generator. I've added tests as well.
#
#I have to pass the locals on the stack to get it to work correctly? Why is
this?
#Is there something I am missing? I did use one less continuation, but it's
#just the continuation to continue the loop of the generator.
require 'test/unit'
class Generator
attr_accessor :currentContext, :contextHistory
def initialize()
self.currentContext=nil
self.reset
end
def next
callcc do |here|
self.currentContext=here
if self.contextHistory.empty?
generatorLoop
else
self.contextHistory.last.call
end
end
end
def backup
self.contextHistory.pop
end
def answer(value, *args)
callcc do |cont|
self.contextHistory.push(cont)
self.currentContext.call(value)
end
args
end
def reset()
self.contextHistory=[]
end
end
class Fibonacci < Generator
def generatorLoop
previous, current=0,1
loop do
#I pass the previous and current local variables as arguments just so
they are returned
#If I don't pass them, weird things happen which makes me think Ruby
#continuations only save part of the state or treats closures special
on the
#stack. The variables are local to the method and not the closure.
But, I still
#think the method's local state should be saved on the stack as well.
Am I missing
#something?
#works
previous, current = answer(current, previous, current)
#doesn't work, but I think it should, what am I missing?
#answer(current)
previous, current = current, previous + current
end
end
end
class TestFibonacci < Test::Unit::TestCase
attr_accessor :to_test
def setup
self.to_test=Fibonacci.new
end
def teardown
self.to_test=nil
end
def test_next
assert_equal(1, self.to_test.next)
assert_equal(1, self.to_test.next)
assert_equal(2, self.to_test.next)
assert_equal(3, self.to_test.next)
assert_equal(5, self.to_test.next)
assert_equal(8, self.to_test.next)
end
def test_back
(1..6).each { self.to_test.next }
assert_equal(13, self.to_test.next)
self.to_test.backup
assert_equal(13, self.to_test.next)
self.to_test.backup
self.to_test.backup
assert_equal(8, self.to_test.next)
assert_equal(13, self.to_test.next)
assert_equal(21, self.to_test.next)
end
end
--
Blaine Buxton, Mad Scientist In Training
My Amps: Smalltalk, Lisp, and Ruby
http://www.blainebuxton.com
_________________________________________________________________
Is your PC infected? Get a FREE online computer virus scan from McAfee®
Security. http://clinic.mcafee.com/clinic/ibuy/campaign.asp?cid=3963