Skip to content

Instantly share code, notes, and snippets.

@loicdescotte
Last active January 15, 2019 09:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save loicdescotte/c4979248d2b2602cca2e25913490cb99 to your computer and use it in GitHub Desktop.
Save loicdescotte/c4979248d2b2602cca2e25913490cb99 to your computer and use it in GitHub Desktop.
Compose errors (or nullables) and async functions in Scala, Kotlin, Typescript
import arrow.core.Either
import arrow.core.Either.Companion.left
import arrow.core.Either.Companion.right
import arrow.core.Option
import arrow.core.Some
import arrow.core.flatMap
import arrow.instances.either.monad.binding
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
fun main(args: Array<String>) {
val total = giveInt2(giveInt(1))
println("total: $total")
val totalWithNullables: Int? = giveNullableInt(1)?.let { giveNullableInt2(it) }
val totalWithOptions: Option<Int> = giveOptionInt(1).flatMap { giveOptionInt2(it) }
val totalWithEithers: Either<String, Int> = giveEitherStringInt(1).flatMap { giveEitherStringInt2(it) }
val totalWithLeftError: Either<String, Int> = giveEitherStringInt(1).flatMap { giveEitherStringInt3(it) }
//GlobalScope.launch {
//use runBlocking here to be able to see the output before the end of the program
runBlocking {
val totalWithEitherCoroutines: Either<String, Int> = giveEitherStringInt(1).flatMap { giveEitherStringInt2(it) }
val asyncResult1 = async { giveEitherStringIntCoroutine(1) }
val asyncResult2 = async { giveEitherStringIntCoroutine2(2) }
val asyncTotalWithEitherCoroutines: Either<String, Int> =
asyncResult1.await().flatMap { r1 -> asyncResult2.await().map { r2 -> r1 + r2 } }
//same example with bind syntax
val awaitedR1 = asyncResult1.await()
val awaitedR2 = asyncResult2.await()
val asyncTotalWithEitherCoroutines2: Either<String, Int> =
binding {
val r1 = awaitedR1.bind()
val r2 = awaitedR2.bind()
r1 + r2
}
}
}
fun giveInt(x: Int): Int {
return x + 1
}
fun giveInt2(x: Int): Int {
return x + 2
}
fun giveNullableInt(x: Int): Int? {
return x + 1
}
fun giveNullableInt2(x: Int): Int? {
return x + 2
}
fun giveOptionInt(x: Int): Option<Int> {
return Some(x + 1)
}
fun giveOptionInt2(x: Int): Option<Int> {
return Some(x + 2)
}
fun giveEitherStringInt(x: Int): Either<String, Int> {
return right(x + 1)
}
fun giveEitherStringInt2(x: Int): Either<String, Int> {
return right(x + 2)
}
fun giveEitherStringInt3(x: Int): Either<String, Int> {
return left("unexpected error")
}
suspend fun giveEitherStringIntCoroutine(x: Int): Either<String, Int> {
delay(1000)
return right(x + 1)
}
suspend fun giveEitherStringIntCoroutine2(x: Int): Either<String, Int> {
delay(1000)
return right(x + 2)
}
import scala.util._
import scala.concurrent.Future
import io.github.hamsters.FutureEither
import io.github.hamsters.MonadTransformers._
import scala.concurrent.ExecutionContext.Implicits.global
def giveInt(x: Int ): Int = x + 1
def giveInt2(x: Int ): Int = x + 2
def giveFuture(x: Int): Future[Int] = Future.successful(x + 1)
def giveFuture2(x: Int ): Future[Int] = Future.successful(x + 2)
def giveOption(x: Int ): Option[Int] = Some(x + 1)
def giveOption2(x: Int ): Option[Int] = Some(x + 2)
def giveEither(x: Int): Either[String, Int] = Right(x + 1)
def giveEither2(x: Int): Either[String, Int] = Right(x + 2)
def giveFutureEither(x: Int ): Future[Either[String, Int]] = Future.successful(Right(x + 1))
def giveFutureEither2(x: Int ): Future[Either[String, Int]] = Future.successful(Right(x + 2))
giveInt2(giveInt(1)) //4
giveOption(1).flatMap(giveOption2) //Some(4)
//OR
for {
a <- giveOption(1)
b <- giveOption2(a)
} yield b // Some(4)
giveEither(1).flatMap(giveEither2) //Right(4)
for {
a <- giveFuture(1)
b <- giveFuture2(a)
} yield b // Future(4)
(for {
a <- FutureEither(giveFutureEither(1))
b <- FutureEither(giveFutureEither2(a))
} yield b).wrapped // Future(Right(4))
import { Option, some, none } from 'fp-ts/lib/Option'
import { Either, left, right } from 'fp-ts/lib/Either'
import { TaskEither, fromEither, tryCatch } from 'fp-ts/lib/TaskEither'
function giveInt(x: number ): number {
return x + 1
}
function giveInt2(x: number ): number {
return x + 2
}
async function giveIntAsync(x: number ): Promise<number> {
const result = await x +1
return result
}
async function giveIntAsync2(x: number ): Promise<number> {
const result = await x +2
return result
}
function giveOptionInt(x: number ): Option<number> {
return some(x + 1)
}
function giveOptionInt2(x: number ): Option<number> {
return some(x + 2)
}
function giveEitherStringInt(x: number ): Either<string, number> {
return right(x + 1)
}
function giveEitherStringInt2(x: number ): Either<string, number> {
return right(x + 2)
}
async function giveEitherStringIntAsync(x: number ): Promise<Either<string, number>> {
const either: Either<string, number> = right(x +1)
const result = await either
return result
}
//create TaskEither from promise
function giveTaskEitherStringInt(x: number): TaskEither<string, number> {
return tryCatch(() => giveIntAsync(x), reason => "oops " + reason)
}
//create TaskEither from Either
function giveTaskEitherStringIn2t(x: number ): TaskEither<string, number> {
return fromEither(giveEitherStringInt2(x))
}
console.log(giveInt2(giveInt(1))) //4
console.log(giveOptionInt(1).chain(giveOptionInt2)) //some(4)
console.log(giveEitherStringInt(1).chain(giveEitherStringInt2)) //right(4)
giveIntAsync(1).then(giveIntAsync2).then(console.log) //4
giveTaskEitherStringInt(1).chain(giveTaskEitherStringIn2t).run().then(console.log) //right(4)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment