Skip to content

Instantly share code, notes, and snippets.

@happy-bracket
Last active December 12, 2019 15:45
Show Gist options
  • Save happy-bracket/eef185c84a3cdad8b6d20eedd961f57e to your computer and use it in GitHub Desktop.
Save happy-bracket/eef185c84a3cdad8b6d20eedd961f57e to your computer and use it in GitHub Desktop.
AsyncTask, but it's a monad!
import android.os.AsyncTask
interface Kind<F, A>
class ForAsync private constructor()
typealias Async<A> = Kind<ForAsync, A>
fun <A> Async<A>.fix() = (this as TrueAsyncTask<A>)
interface Functor<F> {
fun <A, B> lift(f: (A) -> B): (Kind<F, A>) -> Kind<F, B>
fun <A, B> Kind<F, A>.map(f: (A) -> B): Kind<F, B> =
lift(f)(this)
}
interface Monad<F> : Functor<F> {
fun <A> pure(a: A): Kind<F, A>
fun <A, B> Kind<F, A>.flatMap(f: (A) -> Kind<F, B>): Kind<F, B>
}
val AsyncFunctor: Functor<ForAsync> =
object : Functor<ForAsync> {
override fun <A, B> lift(f: (A) -> B): (Kind<ForAsync, A>) -> Kind<ForAsync, B> =
{
TrueAsyncTask { f(it.fix().runner()) }
}
}
val AsyncMonad: Monad<ForAsync> =
object : Monad<ForAsync>, Functor<ForAsync> by AsyncFunctor {
override fun <A> pure(a: A): Kind<ForAsync, A> = TrueAsyncTask { a }
override fun <A, B> Kind<ForAsync, A>.flatMap(f: (A) -> Kind<ForAsync, B>): Kind<ForAsync, B> =
TrueAsyncTask {
val r = fix().runner()
val n = f(r).fix()
n.get()
}
}
class TrueAsyncTask<R>(
val runner: () -> R
) : AsyncTask<Unit, Nothing, R>(), Async<R> {
private lateinit var subscription: (R) -> Unit
override fun doInBackground(vararg params: Unit): R {
val res = runner()
publishProgress()
return res
}
override fun onPostExecute(result: R) {
subscription(result)
}
fun subscribe(sub: (R) -> Unit) {
subscription = sub
this.execute()
}
}
fun <R> async(process: () -> R): TrueAsyncTask<R> =
TrueAsyncTask(process)
fun sample() {
asyncDo {
val token = sampleGetToken().bind()
val tokenHash = token.toLong()
sampleGetUser(tokenHash).bind()
}.fix().subscribe { (id, name) ->
println("id: $id, name: $name")
}
}
fun sampleGetToken() =
async {
Thread.sleep(1000)
"imagine this is token"
}
fun sampleGetUser(tokenHash: Long) =
async {
Thread.sleep(2000)
Pair(tokenHash, "imagine this is user")
}
class AsyncNotation {
fun <A> Async<A>.bind(): A =
fix().get()
}
fun <R> asyncDo(notation: AsyncNotation.() -> R): Async<R> =
async {
AsyncNotation().notation()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment