Skip to content

Instantly share code, notes, and snippets.

@raulraja
Forked from bjonnh/ArrowTrial.kt
Last active January 6, 2019 19:16
Show Gist options
  • Save raulraja/44b34ca2b72f9047318194227380a81d to your computer and use it in GitHub Desktop.
Save raulraja/44b34ca2b72f9047318194227380a81d to your computer and use it in GitHub Desktop.
How to run suspend function in Arrow IOs
import arrow.core.left
import arrow.core.right
import arrow.effects.IO
import arrow.effects.extensions.io.applicativeError.handleErrorWith
import arrow.effects.extensions.io.monad.binding
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import java.time.LocalDateTime
sealed class KnownError : RuntimeException()
object NonExistentReference : KnownError()
object DecodingError : KnownError()
data class UnManagedReturnCode(val status: Int) : KnownError()
data class Call(val a: String, val b: String, val status: Int, val content: String)
suspend fun call(url: String): Call {
delay(1000L)
return Call("10", "2", 200, "{\"value\": \"foo\"}")
}
data class JsonObj(val value: String)
object ArrowTrial {
var lastRun: LocalDateTime = LocalDateTime.now()
var delay: Long = 50
fun calcDelay(): Long {
println("Calculating delay")
return 100L
} // mocked
fun updateDelayFromHeaderData(a: String, b: String) {
println("Updating Delay")
delay = a.toLong() / b.toLong()
} // mocked
fun updateLastQueryTime() = { LocalDateTime.now() }
suspend fun ObjFromJson(content: String): JsonObj? {
delay(1000L)
return JsonObj("Hero")
} // mocked
/**
* There seems to be a bug in arrow effect but normally you can do this with just the following function
* DeferredK { call(doi) }.toIO()
*/
private fun <A> toIO(f: suspend () -> A): IO<A> =
IO.async { _, cb ->
try {
runBlocking { cb(f().right()) }
} catch (e: Throwable) {
cb(e.left())
}
}
fun worksFromDoi(doi: String): IO<JsonObj> =
IO.run {
binding {
IO { calcDelay() }.bind()
val call: Call = toIO { call(doi) }.bind()
IO { updateDelayFromHeaderData(call.a, call.b) }.bind()
IO { updateLastQueryTime() }.bind()
when (call.status) {
200 -> toIO { ObjFromJson(call.content) ?: JsonObj("failed") }
404 -> raiseError(NonExistentReference)
else -> raiseError(UnManagedReturnCode(call.status))
}.handleErrorWith { raiseError(DecodingError) }.bind()
}
}
@JvmStatic
fun main(args: Array<String>) {
println(worksFromDoi("a").unsafeRunSync())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment