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

Re: [scala] Simulating python yield with scala continuations

by Ricky Clarkson :: Rate this Message:

Reply to Author | View in Thread

Bah.  I'd played with C#'s yield and not worked out how to make it
recurse, which you've just showed..

public static IEnumerable<int> Ones() { yield return 1; foreach (var v
in Ones()) yield return v; }

This one's probably most useful as a compiler test case though. :)
The more usual way of writing Ones() would be while (true) yield
return 1;

2009/6/18 Christos KK Loverdos <loverdos@...>:

> 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
>
>
>
>
>
>



--
Ricky Clarkson
Java Programmer, AD Holdings
+44 1565 770804
Skype: ricky_clarkson
Google Talk: ricky.clarkson@...

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