« Return to Thread: [scala] Simulating python yield with scala continuations

[scala] Simulating python yield with scala continuations

by Arnold deVos-3 :: Rate this Message:

Reply to Author | View in Thread

I'm interested in the upcoming continuations support so I thought I would try
to build something similar to the python generators with it.  Here is a scrap
of python:

def generate():
    yield "first"
    for i in range(1,4):
        yield str(i)
    yield "last"

In python this function returns an iterator over the values passed to the
yield statements. The nice thing is: it is lazy and can be used as a
coroutine.  Anyway, if we iterate like this:

for r in generate():
    print r

It prints this:

first
1
2
3
last

Here is a scala version in which a produce() method serves the same role as
python's yield:

object Generator {
    def generate = {
        val g = new Generator[String]
        reset {
            g produce "first"
            g produce 1.toString
            g produce 2.toString
            g produce 3.toString
            g produce "last"
        }
        g
    }

    def main(args: Array[String]) {
        for( a <- generate ) println(a)
    }
}

This also prints

first
1
2
3
last

The Generator class is defined in terms of shift() as follows:

class Generator[A] extends Iterator[A] {
    private var a: A = _                
    private var k: (Unit => Unit) = null
                                       
    def next = {                        
        val a0 = a                      
        val k0 = k                      
        k = null                        
        k0()                            
        a0                              
    }                                  
                                       
    def hasNext = k != null            
                                       
    def produce(a0: A): Unit @ suspendable = {
        a = a0                                
        shift { k0: (Unit => Unit) => k = k0 }
    }
}

But the example is not quite the same as the python because that had a loop in
the generate function.  Lets try that in the scala version, replacing the
generate method with:

    def generate = {
        val g = new Generator[String]
        reset {
            g produce "first"
            for( i <- 1 to 4) { g produce i.toString }
            g produce "last"
        }
        g
    }

But this does not compile:

generator.scala:28: error: type mismatch;
 found   : (Int) => Unit @scala.continuations.cps[Unit,Unit]
 required: (Int) => Unit
            for( i <- 1 to 4) { g produce i.toString }
                 ^
one error found

Substituting a while loop produces a different compile error. Do any
continuation experts/experimenters out there know what the problem is?  

The example was compiled with scala r17271 plus the latest continuations
plugin from trunk as of r18035 for reasons explained in the previous post.  
This may be the problem, I don't know.

- Arnold

 « Return to Thread: [scala] Simulating python yield with scala continuations