Gui*_*Sim 10 continuations scala yield generator 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)
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(())
()
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,gen2因为它不能编译而被注释掉.由于我可以使用while循环轻松迭代列表的内容(请参阅gen3参考资料),我希望foreach循环也能正常工作.
编译错误如下:
no type parameters for method foreach: (f: Int => B)Unit exist so that
it can be applied to arguments (Int => Unit @scala.util.continuations.cpsParam[Unit,Unit])
--- because ---
argument expression's type is not compatible with formal parameter type;
found : Int => Unit @scala.util.continuations.cpsParam[Unit,Unit]
required: Int => ?B
Run Code Online (Sandbox Code Playgroud)
为什么我会得到这个错误,有没有办法解决这个问题比使用while循环更干净?
谢谢
gen2首先让我们看看编译需要什么。
object CpsConversions {\n\n import scala.collection.IterableLike\n import scala.util.continuations._\n\n implicit def cpsIterable[A, Repr](xs: IterableLike[A, Repr]) = new {\n def cps = new {\n def foreach[B](f: A => Any@cpsParam[Unit, Unit]): Unit@cpsParam[Unit, Unit] = {\n val it = xs.iterator\n while(it.hasNext) f(it.next)\n }\n }\n }\n}\n\nobject GenTest {\n\n import CpsConversions.cpsIterable\n val gen2 = new Generator[Int] {\n def produce = {\n var ints = List(1, 2, 3, 42)\n ints.cps.foreach((theInt) => yieldValue(theInt))\n }\n }\nRun Code Online (Sandbox Code Playgroud)\n\n现在让我们看看到底发生了什么。原始文件gen2无法在以下行编译:
ints.foreach((theInt) => yieldValue(theInt))\nRun Code Online (Sandbox Code Playgroud)\n\n由于 的类型yieldValue包含@cpsParam注释,因此延续插件将传递给该foreach方法的函数转换为以下类型之一:
Int => Unit @cpsParam[Unit,Unit]\nRun Code Online (Sandbox Code Playgroud)\n\n在 的层次结构中List[Int],您将看到foreach定义为:
foreach [U] (f: (Int) \xe2\x87\x92 U): Unit\nRun Code Online (Sandbox Code Playgroud)\n\n这是一个问题,因为类型不匹配并且 Scala 不知道如何从Int => U到Int => Unit @cpsParam[Unit,Unit]。为了解决这个问题,我在隐式转换中添加了 CPS 版本foreach,您可以通过调用cps任何IterableLike.
如果这种隐式转换可以在没有显式调用的情况下完成cps,那就太好了,但我还没有找到一种方法让 Scala 编译器认识到这种隐式转换的适用性,以将 new 引入foreach到您的列表中。这可能与编译器使用延续插件的顺序有关,但我对这个过程知之甚少,无法确定。
所以这对 来说一切都很好foreach。您的问题提到了理解,这将需要定义filter、map或中的任何一个flatMap(取决于您的理解中发生的情况)。我已经在上面评论的链接中实现了这些,它扩展了CpsConversions上面的对象以允许一般理解。
| 归档时间: |
|
| 查看次数: |
806 次 |
| 最近记录: |