I am using a state transformer with ListK. I see a ClassCastException that I can reproduce with the minimum failing code below.
Kotlin version: 1.2.41
Arrow version: 0.7.1
import arrow.core.*
import arrow.data.*
import arrow.typeclasses.binding
typealias AnyStack = List<Pair<String, Any>>
fun main(args : Array<String>) {
fun <T:Any> genList(name:String, list: List<T>) = StateT<ForListK, AnyStack, T>(ListK.monad()) { stack ->
ListK(list).map {
stack.plus(name to it) toT it
}
}
fun <T0:Any, T1:Any> genList(name0:String, name1:String, list: List<Tuple2<T0, T1>>) =
StateT<ForListK, AnyStack, Tuple2<T0, T1>>(ListK.monad()) { stack ->
ListK(list).map {
stack.plus(name0 to it.a).plus(name1 to it.b) toT it
}
}
fun intStackOperations() = StateT.monad<ForListK, AnyStack>(ListK.monad()).binding {
val (a,d) = genList("a", "d", listOf(Tuple2(0,"h"))).bind() // no ClassCastException if I comment this line
val b = genList("b", listOf(1,2,3)).bind()
genList("c",(0 until b).toList()).bind()
}.fix()
println(intStackOperations().runS(ListK.monad(), emptyList()).fix())
}
Please let me know if you need more information.
Can you please paste the full stacktrace? I'd like to see which types are being casted. That Any doesn't look great, specially inside coroutines :D
Thanks for your quick response! I wasnt aware of issues with Any in coroutines.
Here is the stack trace.
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to arrow.typeclasses.MonadContinuation
at ExampleKt$main$3$1.doResume(example.kt:24)
at kotlin.coroutines.experimental.jvm.internal.CoroutineImpl.resume(CoroutineImpl.kt:54)
at arrow.typeclasses.MonadContinuation$bind$$inlined$suspendCoroutineOrReturn$lambda$1.invoke(MonadContinuations.kt:59)
at arrow.typeclasses.MonadContinuation$bind$$inlined$suspendCoroutineOrReturn$lambda$1.invoke(MonadContinuations.kt:14)
at arrow.data.StateT$flatMap$$inlined$run$lambda$1$1$1.invoke(StateT.kt:221)
at arrow.data.StateT$flatMap$$inlined$run$lambda$1$1$1.invoke(StateT.kt:39)
at arrow.data.ListK.flatMap(ListK.kt:14)
at arrow.instances.ListKMonadInstance$DefaultImpls.flatMap(listk.kt:69)
at arrow.data.Instance_arrow_instances_ListKMonadInstanceKt$monad$1.flatMap(instance.arrow.instances.ListKMonadInstance.kt:7)
at arrow.data.Instance_arrow_instances_ListKMonadInstanceKt$monad$1.flatMap(instance.arrow.instances.ListKMonadInstance.kt:7)
at arrow.data.StateT$flatMap$$inlined$run$lambda$1$1.invoke(StateT.kt:220)
at arrow.data.StateT$flatMap$$inlined$run$lambda$1$1.invoke(StateT.kt:39)
at arrow.core.PredefKt$andThen$1.invoke(predef.kt:9)
at arrow.data.StateT$run$$inlined$run$lambda$1.invoke(StateT.kt:277)
at arrow.data.StateT$run$$inlined$run$lambda$1.invoke(StateT.kt:39)
at arrow.data.ListK.flatMap(ListK.kt:14)
at arrow.instances.ListKMonadInstance$DefaultImpls.flatMap(listk.kt:69)
at arrow.data.Instance_arrow_instances_ListKMonadInstanceKt$monad$1.flatMap(instance.arrow.instances.ListKMonadInstance.kt:7)
at arrow.data.Instance_arrow_instances_ListKMonadInstanceKt$monad$1.flatMap(instance.arrow.instances.ListKMonadInstance.kt:7)
at arrow.data.StateT.run(StateT.kt:277)
at arrow.data.StateTKt.runM(StateT.kt:27)
at arrow.data.StateT$flatMap$$inlined$run$lambda$1$1$1.invoke(StateT.kt:221)
at arrow.data.StateT$flatMap$$inlined$run$lambda$1$1$1.invoke(StateT.kt:39)
at arrow.data.ListK.flatMap(ListK.kt:14)
at arrow.instances.ListKMonadInstance$DefaultImpls.flatMap(listk.kt:69)
at arrow.data.Instance_arrow_instances_ListKMonadInstanceKt$monad$1.flatMap(instance.arrow.instances.ListKMonadInstance.kt:7)
at arrow.data.Instance_arrow_instances_ListKMonadInstanceKt$monad$1.flatMap(instance.arrow.instances.ListKMonadInstance.kt:7)
at arrow.data.StateT$flatMap$$inlined$run$lambda$1$1.invoke(StateT.kt:220)
at arrow.data.StateT$flatMap$$inlined$run$lambda$1$1.invoke(StateT.kt:39)
at arrow.core.PredefKt$andThen$1.invoke(predef.kt:9)
at arrow.data.StateT$run$$inlined$run$lambda$1.invoke(StateT.kt:277)
at arrow.data.StateT$run$$inlined$run$lambda$1.invoke(StateT.kt:39)
at arrow.data.ListK.flatMap(ListK.kt:14)
at arrow.instances.ListKMonadInstance$DefaultImpls.flatMap(listk.kt:69)
at arrow.data.Instance_arrow_instances_ListKMonadInstanceKt$monad$1.flatMap(instance.arrow.instances.ListKMonadInstance.kt:7)
at arrow.data.Instance_arrow_instances_ListKMonadInstanceKt$monad$1.flatMap(instance.arrow.instances.ListKMonadInstance.kt:7)
at arrow.data.StateT.run(StateT.kt:277)
at arrow.data.StateT.runS(StateT.kt:297)
at ExampleKt.main(example.kt:30)
I modified my code to eschew the Any type by replacing it with a string as follows:
import arrow.core.*
import arrow.data.*
import arrow.typeclasses.binding
typealias AnyStack = List<Pair<String, String>>
fun main(args : Array<String>) {
fun <T:Any> genList(name:String, list: List<T>) = StateT<ForListK, AnyStack, T>(ListK.monad()) { stack ->
ListK(list).map {
stack.plus(name to "$it") toT it
}
}
fun <T0:Any, T1:Any> genList(name0:String, name1:String, list: List<Tuple2<T0, T1>>) =
StateT<ForListK, AnyStack, Tuple2<T0, T1>>(ListK.monad()) { stack ->
ListK(list).map {
stack.plus(name0 to "${it.a}").plus(name1 to "${it.b}") toT it
}
}
fun intStackOperations() = StateT.monad<ForListK, AnyStack>(ListK.monad()).binding {
val (a,d) = genList("a", "d", listOf(Tuple2(0,"h"))).bind() // no ClassCastException if I comment this line
val b = genList("b", listOf(1,2,3)).bind()
genList("c",(0 until b).toList()).bind()
}.fix()
println(intStackOperations().runS(ListK.monad(), emptyList()).fix())
}
I still see the exceptionwith a similar stack trace though.
Let's rule out coroutines. Can you please rewrite the comprehension to use flatMap instead?
Thats a great suggestion. I rewrote with flatMap. This doesnt throw the exception!
fun intStackOperations() =
genList("a", "d", listOf(Tuple2(0, "h"))).flatMap(ListK.monad()){
genList("b", listOf(1, 2, 3)).flatMap(ListK.monad()){
genList("c", (0 until it).toList())
}
}
FWIW, I see that the following implementation with comprehensions works. The only difference is that I dont have a val (a,d) assignment in the first comprehension.
fun intStackOperations() = StateT.monad<ForListK, AnyStack>(ListK.monad()).binding {
// val (a,d) = genList("a", "d", listOf(Tuple2(0,"h"))).bind() // ClassCastException with this line
genList("a", "d", listOf(Tuple2(0,"h"))).bind() // no ClassCastException
val b = genList("b", listOf(1,2,3)).bind()
genList("c",(0 until b).toList()).bind()
}.fix()
I tried a bit of debugging myself but couldnt figure out what was causing this exception.
Can you please hint the types for (a,d)? It may be a case where type inference just farted.
Thanks for your time! Sorry for the absurd names of the variables.
I tried your suggestion and still see an exception.
fun intStackOperations() = StateT.monad<ForListK, AnyStack>(ListK.monad()).binding {
val (a:Int, d:String) = genList("a", "d", listOf(Tuple2(0,"h"))).bind() // ClassCastException with this line
// genList("a", "d", listOf(Tuple2(0,"h"))).bind() // no ClassCastException
val b = genList("b", listOf(1,2,3)).bind()
genList("c",(0 until b).toList()).bind()
}.fix()
Try not to destructure it.
I was trying it out as I saw your reply :-). Not destructuring it and also supplying type hint still has the exception.
fun intStackOperations() = StateT.monad<ForListK, AnyStack>(ListK.monad()).binding {
// val (a:Int, d:String) = genList("a", "d", listOf(Tuple2(0,"h"))).bind() // ClassCastException with this line
val a_d:Tuple2<Int, String> = genList("a", "d", listOf(Tuple2(0,"h"))).bind() // ClassCastException with this line
// genList("a", "d", listOf(Tuple2(0,"h"))).bind() // no ClassCastException
val b = genList("b", listOf(1,2,3)).bind()
genList("c",(0 until b).toList()).bind()
}.fix()
Okay, I believe with this info you can raise a ticket to JetBrains about coroutines rewritting code with the wrong type inference :D Try here: https://youtrack.jetbrains.com/issues/kt
FYI, the JetBrains ticket got a response. To summarize, they say "Basically, the issue is caused by unconventional use of coroutines in the library (even if this particular bug is fixed on the library side, this use case of coroutines anyway seems to be rather unsupported)."
Cool, I spoke to them and there may be a solution here: https://github.com/h0tk3y/probabilistik/blob/master/src/main/kotlin/com/github/h0tk3y/probabilistik/ContinuationUtils.kt
@pakoito looking forward to hearing more about it.
Most helpful comment
@pakoito looking forward to hearing more about it.