延续和推导式——有什么不兼容之处?
我是 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(())
()
}
}
如您所见,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
为什么我会收到此错误,有没有办法用比 while 循环更干净的方法来解决此问题?
谢谢
I am new to Scala and trying to wrap my head around continuations
I'm trying to reproduce the yield return
C# statement.
Following this post, I have written the following code :
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(())
()
}
}
As you can see, gen2
is commented out as it does not compile. Since I can easily iterate over the content of a list using a while loop (see gen3
), I expected the foreach loop to work just as well.
The compilation error is the following :
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
Why do I get this error and is there a way to work around this with something cleaner than a while loop?
Thank you
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
首先让我们看看如何编译
gen2
。现在让我们看看到底发生了什么。原始的 gen2 无法在以下行编译:
由于
yieldValue
的类型包含@cpsParam
注释,延续插件会转换传递的函数将foreach
方法转换为以下类型之一:在
List[Int]
的层次结构中,您会看到foreach
定义为:是一个问题,因为类型不匹配Scala 不知道如何从
Int => 获取U
到Int =>单位@cpsParam[单位,单位]
。为了解决这个问题,我在隐式转换中添加了 CPS 版本的foreach
,您可以通过在任何IterableLike
上调用cps
来访问它。如果这种隐式转换可以在没有显式 cps 调用的情况下完成,那就太好了,但我还没有找到一种方法让 Scala 编译器认识到这种隐式转换对新
cps
调用的适用性。 code>foreach 到您的列表中。这可能与编译器使用延续插件的顺序有关,但我对这个过程知之甚少,无法确定。所以对于
foreach
来说这一切都很好。您的问题提到了理解,这将需要定义filter
、map
或flatMap
中的任何一个(取决于您的 for 中发生的情况)理解)。我已经在上面评论的链接中实现了这些,它扩展了上面的 CpsConversions 对象以允许一般的理解。First let's look at what it will take to get
gen2
to compile.Now let's take a look at what's going on. The original
gen2
fails to compile on the following line:Since the type of
yieldValue
includes an@cpsParam
annotation, the continuations plugin transforms the function passed to theforeach
method to one of type:Way up in the hierarchy of
List[Int]
, you'll seeforeach
defined as:This is a problem, as the types do not match and Scala doesn't know how to get from
Int => U
toInt => Unit @cpsParam[Unit,Unit]
. To fix it, I added the CPS version offoreach
in an implicit conversion, which you can access by callingcps
on anyIterableLike
.It would be very nice if this implicit conversion could be done without the explicit
cps
call, but I have not found a way to make the Scala compiler recognize the applicability of such an implicit conversion to pimp the newforeach
onto your list. This might have to do with the order in which the compiler uses the continuations plugin, but I know far too little about this process to be sure.So that's all well and good for
foreach
. Your question mentions for comprehensions, which will require any offilter
,map
, orflatMap
to be defined (depending on what goes on in your for comprehension). I have implemented these in the link in my above comment, which extends theCpsConversions
object above to allow for general for comprehensions.