-
-
Save raulraja/44b34ca2b72f9047318194227380a81d to your computer and use it in GitHub Desktop.
How to run suspend function in Arrow IOs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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