Thursday, March 3, 2011

Python equivalent of continuations with Ruby

What is the Python equivalent of the following code in Ruby?

def loop
  cont=nil
  for i in 1..4
    puts i
    callcc {|continuation| cont=continuation} if i==2
  end
  return cont
end

> c=loop
1
2
3
4
> c.call
3
4

Reference: Secrets of lightweight development success, Part 9: Continuations-based frameworks

From stackoverflow
  • take a look at the yield statement to make generators.

    I don't speak any ruby, but it seems like you're looking for this:

    def loop():
        for i in xrange(1,5):
            print i
            if i == 2:
                yield
    
    
    for i in loop():
        print "pass"
    

    Edit: I realize this is basically a specialization of real continuations, but it should be sufficient for most purposes. Use yield to return the continuation and the .next() message on the generator (returned by just calling loop()) to reenter.

    J.F. Sebastian : It is not that easy, see http://stackoverflow.com/questions/312794/#313073
  • The article you quoted contains a link to Continuations Made Simple And Illustrated in the Resources section, which talks about continuations in the Python language.

  • def loop():    
        def f(i, cont=[None]):        
            for i in range(i, 5):
                print i
                if i == 2:
                    cont[0] = lambda i=i+1: f(i)
            return cont[0]
        return f(1)
    
    if __name__ == '__main__':
        c = loop()
        c()
    
  • Using generator_tools (to install: '$ easy_install generator_tools'):

    from generator_tools import copy_generator
    
    def _callg(generator, generator_copy=None):
        for _ in generator: # run to the end
            pass
        if generator_copy is not None:
            return lambda: _callg(copy_generator(generator_copy))
    
    def loop(c):
        c.next() # advance to yield's expression
        return _callg(c, copy_generator(c))
    
    if __name__ == '__main__':
        def loop_gen():
            i = 1
            while i <= 4:
                print i
                if i == 2:
                    yield
                i += 1
    
        c = loop(loop_gen())
        print("c:", c)
        for _ in range(2):
            print("c():", c())
    

    Output:

    1
    2
    3
    4
    ('c:', <function <lambda> at 0x00A9AC70>)
    3
    4
    ('c():', None)
    3
    4
    ('c():', None)
    

0 comments:

Post a Comment