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

Re: [scala] Simulating python yield with scala continuations

by Christos KK Loverdos :: Rate this Message:

Reply to Author | View in Thread

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