Reputation: 529
I'm trying to build a coroutine framework to enable batch data fetching by stepping through each data-dependent function in parallel. Here is what I have so far: http://pastie.org/7147798
This doesn't work
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))
}
I get the following error
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
This works
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))
}
}
This doesn't work
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)
}
}
I get the following error
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
This works
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)
}
}
But I get the following warning
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
Upvotes: 2
Views: 286
Reputation: 41646
Although I still don't quite understand continuations myself, as best as I can tell, the key issue in your example is that your code does not always supply a shift
to the reset
.
The compiler expects to find some shift
nested inside the reset
. It will then CPS transform the shift
into a ControlContext][A, B, C]
and the code that happens after the shift
into a ControlContext.map
call.
Because you have an if
statement, in the case where the else branch is taken, there is no nested shift
:
reset {
if (false) {
shift { ... }
}
Result(cached(id)) // no shift
}
Same with
reset {
if (false) {
shift { ... }
} else {
Result(cached(id)) // no shift
}
}
That cannot be transformed into valid CPS code.
It seems you could have the reset inside the if branch or supply a trivial shift statement to the else branch:
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))
}
}
}
Edit: It does seems there is some inconsistencies on how the cps plugin infers the types. For example:
var b = false
def test[A](a: A) = reset {
if (b) {
a
} else {
shift{ (k: Unit => A) => k() }
a
}
}
Running compilation with the -Xprint:selectivecps
options shows that the compiler infers the type as Reset[A, Nothing]
then running the code will produce an error at runtime. If the if is reversed as:
var b = false
def test[A](a: A) = reset {
if (b) {
shift{ (k: Unit => A) => k() }
a
} else {
a
}
}
Then the compiler correctly infers reset[A, A]
. If I provide the type parameters to reset
like test[A](a: A) = reset[A, A] {
then it works in both cases.
Maybe specifying the type parameters to reset
and shift
and also instead of using Result(5)
, using the shiftUnit[A, B, C]
method will help with reducing inconsistencies.
Upvotes: 1