« 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 2, I just looked up 'Bah' in the dictionary, and it is  
close in meaning to the greek 'Μπα', whose sound can be exactly the  
same :)

On Jun 18, 2009, at 10:20 PM, Ricky Clarkson wrote:

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

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





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