相当于Python生成器的Scala?

是否有可能在Scala中实现等价于Python yield语句的地方,它记住函数的本地状态,并在每次调用时产生下一个值?

我想有这样的东西把一个recursion函数转换成一个迭代器。 有点像这样:

 # this is python def foo(i): yield i if i > 0: for j in foo(i - 1): yield j for i in foo(5): print i 

除此之外, foo可能会更复杂,并且通过一些非循环对象图来重复出现。

其他编辑:让我添加一个更复杂的例子(但仍然很简单):我可以写一个简单的recursion函数,

 // this is Scala def printClass(clazz:Class[_], indent:String=""): Unit = { clazz match { case null => case _ => println(indent + clazz) printClass(clazz.getSuperclass, indent + " ") for (c <- clazz.getInterfaces) { printClass(c, indent + " ") } } } 

理想情况下,我想有一个图书馆,使我可以轻松地更改几个语句,并作为一个迭代器工作:

 // this is not Scala def yieldClass(clazz:Class[_]): Iterator[Class[_]] = { clazz match { case null => case _ => sudoYield clazz for (c <- yieldClass(clazz.getSuperclass)) sudoYield c for (c <- clazz.getInterfaces; d <- yieldClasss(c)) sudoYield d } } 

似乎延续允许这样做,但我不明白的shift/reset概念。 延续最终会使它成为主要的编译器,是否有可能提取出库中的复杂性?

编辑2:在另一个线程中检查Rich的答案 。

虽然Python生成器很酷,但试图重复它们并不是在Scala中最好的方法。 例如,下面的代码可以完成与你想要的相同的工作:

 def classStream(clazz: Class[_]): Stream[Class[_]] = clazz match { case null => Stream.empty case _ => ( clazz #:: classStream(clazz.getSuperclass) #::: clazz.getInterfaces.toStream.flatMap(classStream) #::: Stream.empty ) } 

在这个stream中,stream是生成的,所以它不会处理任何的元素,直到被询问,你可以通过运行这个来validation:

 def classStream(clazz: Class[_]): Stream[Class[_]] = clazz match { case null => Stream.empty case _ => ( clazz #:: { println(clazz.toString+": super"); classStream(clazz.getSuperclass) } #::: { println(clazz.toString+": interfaces"); clazz.getInterfaces.toStream.flatMap(classStream) } #::: Stream.empty ) } 

只需在生成的Stream上调用.iterator就可以将结果转换为Iterator

 def classIterator(clazz: Class[_]): Iterator[Class[_]] = classStream(clazz).iterator 

使用Streamfoo定义将如下呈现:

 scala> def foo(i: Int): Stream[Int] = i #:: (if (i > 0) foo(i - 1) else Stream.empty) foo: (i: Int)Stream[Int] scala> foo(5) foreach println 5 4 3 2 1 0 

另一个select是连接各种迭代器,注意不要预先计算它们。 下面是一个例子,还有debugging消息来帮助跟踪执行情况:

 def yieldClass(clazz: Class[_]): Iterator[Class[_]] = clazz match { case null => println("empty"); Iterator.empty case _ => def thisIterator = { println("self of "+clazz); Iterator(clazz) } def superIterator = { println("super of "+clazz); yieldClass(clazz.getSuperclass) } def interfacesIterator = { println("interfaces of "+clazz); clazz.getInterfaces.iterator flatMap yieldClass } thisIterator ++ superIterator ++ interfacesIterator } 

这很接近你的代码。 而不是sudoYield ,我有定义,然后按照我的意愿将它们连接起来。

所以,虽然这是一个无法回答的问题,我只是认为你在这里吠叫错了树。 试图在Scala中编写Python肯定是徒劳的。 更加努力地完成相同目标的Scala成语。

另一个延续插件的解决scheme,这个时候或多或less封装发电机types,

 import scala.continuations._ import scala.continuations.ControlContext._ object Test { def loopWhile(cond: =>Boolean)(body: =>(Unit @suspendable)): Unit @suspendable = { if (cond) { body loopWhile(cond)(body) } else () } abstract class Generator[T] { var producerCont : (Unit => Unit) = null var consumerCont : (T => Unit) = null protected def body : Unit @suspendable reset { body } def generate(t : T) : Unit @suspendable = shift { (k : Unit => Unit) => { producerCont = k if (consumerCont != null) consumerCont(t) } } def next : T @suspendable = shift { (k : T => Unit) => { consumerCont = k if (producerCont != null) producerCont() } } } def main(args: Array[String]) { val g = new Generator[Int] { def body = { var i = 0 loopWhile(i < 10) { generate(i) i += 1 } } } reset { loopWhile(true) { println("Generated: "+g.next) } } } } 

要做到这一点,我认为你需要延续插件 。

一个天真的实现(徒手,没有编译/检查):

 def iterator = new { private[this] var done = false // Define your yielding state here // This generator yields: 3, 13, 0, 1, 3, 6, 26, 27 private[this] var state: Unit=>Int = reset { var x = 3 giveItUp(x) x += 10 giveItUp(x) x = 0 giveItUp(x) List(1,2,3).foreach { i => x += i; giveItUp(x) } x += 20 giveItUp(x) x += 1 done = true x } // Well, "yield" is a keyword, so how about giveItUp? private[this] def giveItUp(i: Int) = shift { k: (Unit=>Int) => state = k i } def hasNext = !done def next = state() } 

现在发生的情况是,任何shift调用都会将控制stream程从调用的位置捕获到调用的reset块的末尾。这将作为kparameter passing给移位函数。

所以,在上面的例子中,每个giveItUp(x)返回giveItUp(x)的值(直到那个点),并将其余的计算保存在statevariables中。 它是由hasNextnext方法从外部驱动的。

去温柔,这显然是一个可怕的方式来实现这一点。 但最好我可以在没有编译器的情况下深夜做。

for (e <- Producer) f(e) Scala for循环转化为一个foreach调用,而不是直接进入iterator / next

foreach我们不需要对对象的创build进行线性化,并将它们放在一个地方,因为迭代器的next需要。 消费者函数f可以被插入多次,恰好在需要的地方(即创build对象的地方)。

这使得在Scala中使用Traversable / foreach实现简单高效的生成Traversable例。


最初的Foo例子:

 case class Countdown(start: Int) extends Traversable[Int] { def foreach[U](f: Int => U) { var j = start while (j >= 0) {f(j); j -= 1} } } for (i <- Countdown(5)) println(i) // or equivalent: Countdown(5) foreach println 

最初的printClass例子:

  // v1 (without indentation) case class ClassStructure(c: Class[_]) { def foreach[U](f: Class[_] => U) { if (c eq null) return f(c) ClassStructure(c.getSuperclass) foreach f c.getInterfaces foreach (ClassStructure(_) foreach f) } } for (c <- ClassStructure(<foo/>.getClass)) println(c) // or equivalent: ClassStructure(<foo/>.getClass) foreach println 

或者缩进:

  // v2 (with indentation) case class ClassWithIndent(c: Class[_], indent: String = "") { override def toString = indent + c } implicit def Class2WithIndent(c: Class[_]) = ClassWithIndent(c) case class ClassStructure(cwi: ClassWithIndent) { def foreach[U](f: ClassWithIndent => U) { if (cwi.c eq null) return f(cwi) ClassStructure(ClassWithIndent(cwi.c.getSuperclass, cwi.indent + " ")) foreach f cwi.c.getInterfaces foreach (i => ClassStructure(ClassWithIndent(i, cwi.indent + " ")) foreach f) } } for (c <- ClassStructure(<foo/>.getClass)) println(c) // or equivalent: ClassStructure(<foo/>.getClass) foreach println 

输出:

 class scala.xml.Elem class scala.xml.Node class scala.xml.NodeSeq class java.lang.Object interface scala.collection.immutable.Seq interface scala.collection.immutable.Iterable interface scala.collection.immutable.Traversable interface scala.collection.Traversable interface scala.collection.TraversableLike interface scala.collection.generic.HasNewBuilder interface scala.collection.generic.FilterMonadic interface scala.collection.TraversableOnce interface scala.ScalaObject interface scala.ScalaObject interface scala.collection.generic.GenericTraversableTemplate interface scala.collection.generic.HasNewBuilder interface scala.ScalaObject interface scala.ScalaObject interface scala.collection.generic.GenericTraversableTemplate interface scala.collection.generic.HasNewBuilder interface scala.ScalaObject interface scala.collection.TraversableLike interface scala.collection.generic.HasNewBuilder interface scala.collection.generic.FilterMonadic interface scala.collection.TraversableOnce interface scala.ScalaObject interface scala.ScalaObject interface scala.Immutable interface scala.ScalaObject interface scala.collection.Iterable interface scala.collection.Traversable interface scala.collection.TraversableLike interface scala.collection.generic.HasNewBuilder interface scala.collection.generic.FilterMonadic interface scala.collection.TraversableOnce interface scala.ScalaObject interface scala.ScalaObject interface scala.collection.generic.GenericTraversableTemplate interface scala.collection.generic.HasNewBuilder interface scala.ScalaObject interface scala.ScalaObject interface scala.collection.generic.GenericTraversableTemplate interface scala.collection.generic.HasNewBuilder interface scala.ScalaObject interface scala.collection.IterableLike interface scala.Equals interface scala.collection.TraversableLike interface scala.collection.generic.HasNewBuilder interface scala.collection.generic.FilterMonadic interface scala.collection.TraversableOnce interface scala.ScalaObject interface scala.ScalaObject interface scala.ScalaObject interface scala.ScalaObject interface scala.collection.generic.GenericTraversableTemplate interface scala.collection.generic.HasNewBuilder interface scala.ScalaObject interface scala.collection.IterableLike interface scala.Equals interface scala.collection.TraversableLike interface scala.collection.generic.HasNewBuilder interface scala.collection.generic.FilterMonadic interface scala.collection.TraversableOnce interface scala.ScalaObject interface scala.ScalaObject interface scala.ScalaObject interface scala.ScalaObject interface scala.collection.Seq interface scala.PartialFunction interface scala.Function1 interface scala.ScalaObject interface scala.ScalaObject interface scala.collection.Iterable interface scala.collection.Traversable interface scala.collection.TraversableLike interface scala.collection.generic.HasNewBuilder interface scala.collection.generic.FilterMonadic interface scala.collection.TraversableOnce interface scala.ScalaObject interface scala.ScalaObject interface scala.collection.generic.GenericTraversableTemplate interface scala.collection.generic.HasNewBuilder interface scala.ScalaObject interface scala.ScalaObject interface scala.collection.generic.GenericTraversableTemplate interface scala.collection.generic.HasNewBuilder interface scala.ScalaObject interface scala.collection.IterableLike interface scala.Equals interface scala.collection.TraversableLike interface scala.collection.generic.HasNewBuilder interface scala.collection.generic.FilterMonadic interface scala.collection.TraversableOnce interface scala.ScalaObject interface scala.ScalaObject interface scala.ScalaObject interface scala.ScalaObject interface scala.collection.generic.GenericTraversableTemplate interface scala.collection.generic.HasNewBuilder interface scala.ScalaObject interface scala.collection.SeqLike interface scala.collection.IterableLike interface scala.Equals interface scala.collection.TraversableLike interface scala.collection.generic.HasNewBuilder interface scala.collection.generic.FilterMonadic interface scala.collection.TraversableOnce interface scala.ScalaObject interface scala.ScalaObject interface scala.ScalaObject interface scala.ScalaObject interface scala.ScalaObject interface scala.collection.generic.GenericTraversableTemplate interface scala.collection.generic.HasNewBuilder interface scala.ScalaObject interface scala.collection.SeqLike interface scala.collection.IterableLike interface scala.Equals interface scala.collection.TraversableLike interface scala.collection.generic.HasNewBuilder interface scala.collection.generic.FilterMonadic interface scala.collection.TraversableOnce interface scala.ScalaObject interface scala.ScalaObject interface scala.ScalaObject interface scala.ScalaObject interface scala.ScalaObject interface scala.collection.SeqLike interface scala.collection.IterableLike interface scala.Equals interface scala.collection.TraversableLike interface scala.collection.generic.HasNewBuilder interface scala.collection.generic.FilterMonadic interface scala.collection.TraversableOnce interface scala.ScalaObject interface scala.ScalaObject interface scala.ScalaObject interface scala.ScalaObject interface scala.xml.Equality interface scala.Equals interface scala.ScalaObject interface scala.ScalaObject interface scala.ScalaObject interface scala.ScalaObject interface java.io.Serializable