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

Re: [scala] Simulating python yield with scala continuations

by Jorge Ortiz-3 :: Rate this Message:

Reply to Author | View in Thread

Again, probably not as pretty, but it can be done with lazy collections:

  case class Tree(left: Option[Tree], label: String, right: Option[Tree])

  def inorder(t: Tree): Iterator[String] = {
    t.left.elements.flatMap(inorder) append
    Iterator.single(t.label) append        
    t.right.elements.flatMap(inorder)      
  }

  val t = Tree(Some(Tree(None, "left", None)), "center", Some(Tree(None, "right",  None)))

  for (x <- inorder(t)) println(x)

--j

On Thu, Jun 18, 2009 at 12:48 AM, Christos KK Loverdos <loverdos@...> wrote:
As a side note, I think the point with Python's generators is best given with tree traversal:

def inorder(t):
 if t:
   for x in inorder(t.left):
     yield x
   yield t.label
   for x in inorder(t.right):
     yield x

No explicit state management, no result building up. As soon as I have a value, I yield it.


On Jun 18, 2009, at 6:56 AM, Arnold deVos wrote:

Well yes, you can always string together pieces with append, andThen and so on
but continuations are all about coding this sort of thing in direct-style.
The benefit is not so clear with a simple example like mine.

But the point of the post is not to motivate continuations.  I am wanting
exchange knowledge with others that already do want to continuations and tease
out bugs in the implementation.

-- Arnold

On Thu, 18 Jun 2009 01:33:57 pm Jorge Ortiz wrote:
Scala has lazy collections, which, AFAIK, can do whatever generators can
without needing the continuations plugin.

 val generate =
  (
    Array("first").projection append
    (1 to 4).map(_.toString) append
    Array("last").projection
  ).elements

 for (r <- generate) println(r)

The code is, admittedly, a little ugly, but could be made a little cleaner
with 2.8 collections.

(Note this won't work in the interpreter, as the interpreter calls toString
on "generate", which forces its evaluation. If you suppress the call to
toString, it works as specified.)

--j

On Wed, Jun 17, 2009 at 7:17 PM, Arnold deVos <

adv-list-scala@...> wrote:
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



--
 __~O
-\ <,       Christos KK Loverdos
(*)/ (*)      http://ckkloverdos.com






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