Scala 延续和理解——什么';什么是不相容性?

Scala 延续和理解——什么';什么是不相容性?,scala,generator,yield,continuations,continuation-passing,Scala,Generator,Yield,Continuations,Continuation Passing,我对Scala还不熟悉,我正试图用头脑去思考续集 我试图重现yield-returnC#语句 下面,我编写了以下代码: package com.company.scalatest import scala.util.continuations._; object GenTest { val gen = new Generator[Int] { def produce = { yieldValue(1) yieldValue(2) yieldV

我对Scala还不熟悉,我正试图用头脑去思考续集 我试图重现
yield-return
C#语句

下面,我编写了以下代码:

package com.company.scalatest

import scala.util.continuations._;

object GenTest {

  val gen = new Generator[Int] {
    def produce = {
      yieldValue(1)
      yieldValue(2)
      yieldValue(3)
      yieldValue(42)
    }
  }
  // Does not compile :(

  //  val gen2 = new Generator[Int] {
  //    def produce = {
  //      var ints = List(1, 2, 3, 42);
  //
  //      ints.foreach((theInt) => yieldValue(theInt));
  //    }
  //  }

  // But this works?
  val gen3 = new Generator[Int] {
    def produce = {
      var ints = List(1, 2, 3, 42);
      var i = 0;
      while (i < ints.length) {
        yieldValue(ints(i));
        i = i + 1;
      }
    }
  }

  def main(args: Array[String]): Unit = {
    gen.foreach(println);
    //    gen2.foreach(println);
    gen3.foreach(println);
  }
}

abstract class Generator[E] {

  var loopFn: (E => Unit) = null

  def produce(): Unit @cps[Unit]

  def foreach(f: => (E => Unit)): Unit = {
    loopFn = f
    reset[Unit, Unit](produce)
  }

  def yieldValue(value: E) =
    shift { genK: (Unit => Unit) =>
      loopFn(value)
      genK(())
      ()
    }
}
为什么我会出现这个错误,有没有比while循环更干净的方法来解决这个问题?


谢谢

首先让我们看看编译
gen2
需要什么

object CpsConversions {

  import scala.collection.IterableLike
  import scala.util.continuations._

  implicit def cpsIterable[A, Repr](xs: IterableLike[A, Repr]) = new {
    def cps = new {
      def foreach[B](f: A => Any@cpsParam[Unit, Unit]): Unit@cpsParam[Unit, Unit] = {
        val it = xs.iterator
        while(it.hasNext) f(it.next)
      }
    }
  }
}

object GenTest {

  import CpsConversions.cpsIterable
  val gen2 = new Generator[Int] {
    def produce = {
      var ints = List(1, 2, 3, 42)
      ints.cps.foreach((theInt) => yieldValue(theInt))
    }
  }
现在让我们来看看发生了什么。原始的
gen2
无法在以下行编译:

ints.foreach((theInt) => yieldValue(theInt))
由于
yieldValue
的类型包括
@cpsParam
注释,因此continuations插件将传递给
foreach
方法的函数转换为以下类型之一:

Int => Unit @cpsParam[Unit,Unit]
List[Int]
的层次结构中,您将看到
foreach
定义为:

foreach [U] (f: (Int) ⇒ U): Unit
这是一个问题,因为类型不匹配,Scala不知道如何从
Int=>U
Int=>Unit@cpsParam[Unit,Unit]
。为了修复它,我在隐式转换中添加了
foreach
的CPS版本,您可以通过在任何
IterableLike
上调用
CPS
来访问它

如果这种隐式转换不需要显式的
cps
调用,那就太好了,但是我还没有找到一种方法让Scala编译器认识到这种隐式转换的适用性,从而将新的
foreach
推到您的列表中。这可能与编译器使用continuations插件的顺序有关,但我对这个过程知之甚少,无法确定


因此,这对
foreach
来说都很好。您的问题涉及理解,这将需要定义
过滤器
映射
、或
平面映射
(取决于理解过程中的内容)。我已经在我上面的评论中的链接中实现了这些,它扩展了上面的
cpscoverations
对象,以便于理解。

我不想找到一个答案,告诉我如何使用Scala continuations重现“收益率回报”。我正在寻找示例中的“gen2”不起作用的原因。“收益回报”正是我遇到这个问题的背景。我将主题改为更适合您实际问题的主题。为什么
gen2
不起作用的答案主要与continuations编译器插件如何将移位和重置转换为基础ControlContext实例有关。今天晚些时候,我会给出一个正确的答案,但现在我写了一篇关于这个主题的简介:
foreach [U] (f: (Int) ⇒ U): Unit