我正在尝试构建一个协程框架,通过并行逐步执行每个数据相关的函数来启用批量数据获取。以下是我到目前为止:http://pastie.org/7147798
这不起作用
def get(id: Long) = reset {
// Is it not already cached?
if (!cached.isDefinedAt(id)) {
// Store the ID we want to fetch.
queued += id
// Come back later...
shift { fetch[Object]() } : Seq[Any] @cps[ExecState[Object]]
}
// We should have the ID fetched now.
Result(cached(id))
}
我收到以下错误
ashoat@ashoatmbp [~/project]# scala -P:continuations:enable Loader.scala
/Users/ashoat/project/Loader.scala:134: error: type mismatch;
found : Unit
required: Any @util.continuations.package.cps[Main.$anon.Loader.ExecState[Main.$anon.Loader.Object]]
if (!cached.isDefinedAt(id)) {
^
one error found
此作品
def get(id: Long) = reset {
// Is it not already cached?
if (!cached.isDefinedAt(id)) {
// Store the ID we want to fetch.
queued += id
// Come back later...
shift { fetch[Object]() } : Seq[Any] @cps[ExecState[Object]]
// We should have the ID fetched now.
Result(cached(id))
} else {
// We should have the ID fetched now.
Result(cached(id))
}
}
这不起作用
val getFive = reset {
if (true) {
Result(5)
} else {
val seq: Seq[Any] = shift { fetch[Int](Object.get(15181990251L)) }
val Seq(obj: Object) = seq
Result(obj.fields("test").toInt)
}
}
我收到以下错误
ashoat@ashoatmbp [~/project]# scala -P:continuations:enable Loader.scala
/Users/ashoat/project/Loader.scala:170: error: cannot cps-transform expression new this.Loader.Result[Int](5): type arguments [this.Loader.Result[Int],this.Loader.Result[Int],Nothing] do not conform to method shiftUnit's type parameter bounds [A,B,C >: B]
Result(5)// : Result[Int] @cps[Result[Int]]
^
one error found
此作品
val getFive = reset {
if (true) {
Result(5) : Result[Int] @cps[Result[Int]]
} else {
val seq: Seq[Any] = shift { fetch[Int](Object.get(15181990251L)) }
val Seq(obj: Object) = seq
Result(obj.fields("test").toInt)
}
}
但我收到以下警告
ashoat@ashoatmbp [~/project]# scala -P:continuations:enable Loader.scala
/Users/ashoat/project/Loader.scala:170: warning: expression (new this.Loader.Result[Int](5): this.Loader.Result[Int]) is cps-transformed unexpectedly
Result(5) : Result[Int] @cps[Result[Int]]
^
one warning found
8
答案 0 :(得分:1)
虽然我仍然不太了解 continuations ,但就我所知,您的示例中的关键问题是您的代码并不总是向shift
提供reset
shift
。
编译器希望在reset
内嵌套shift
。然后,它会将shift
转换为ControlContext][A, B, C]
,并将ControlContext.map
之后的代码转换为if
调用。
因为您有shift
语句,如果采用 else 分支,则没有嵌套reset {
if (false) {
shift { ... }
}
Result(cached(id)) // no shift
}
:
reset {
if (false) {
shift { ... }
} else {
Result(cached(id)) // no shift
}
}
与
相同if (!cached.isDefinedAt(id)) reset {
shift { ... }
Result(cached(id))
} else {
Result(cached(id))
}
// or
reset {
if (!cached.isDefinedAt(id)) {
shift { ... }
Result(cached(id))
} else {
shift[Result[Object], ExecState[Object], ExecState[Object]] { k =>
Result(cached(id))
}
}
}
无法转换为有效的CPS代码。
似乎你可以在if分支中重置或者向else分支提供一个简单的shift语句:
var b = false
def test[A](a: A) = reset {
if (b) {
a
} else {
shift{ (k: Unit => A) => k() }
a
}
}
编辑:似乎cps插件如何推断出这些类型存在一些不一致之处。例如:
-Xprint:selectivecps
使用Reset[A, Nothing]
选项运行编译显示编译器将类型推断为var b = false
def test[A](a: A) = reset {
if (b) {
shift{ (k: Unit => A) => k() }
a
} else {
a
}
}
,然后运行代码将在运行时产生错误。如果 if 反转为:
reset[A, A]
然后编译器正确推断出reset
。如果我将类型参数提供给test[A](a: A) = reset[A, A] {
reset
,那么它在两种情况下都有效。
也许指定shift
和Result(5)
的类型参数,而不是使用shiftUnit[A, B, C]
,使用{{1}}方法有助于减少不一致性。