Search code examples
kotliniofunctional-programmingeitherarrow-kt

For comprehensions with kotlin and arrow-kt library


I use arrow-kt library and I'm trying to employ Either and IO within the same for comprehension.

Say I have the next piece of code:

IO.monad().binding {
    val ans: Either<Error, Data> = someFunctionThatReturnsEitherWrappedInIO().bind()
}

Now, I'd like to use binding on the ans:

val data: Data = ans.bind() // My intent

Is it possible to do It whithin the scope of the first piece of code?

Currently I'm trying to nest an Either binding within the scope of the IO binding, but I'm not sure this is a good practice:

IO.monad().binding {
    val ans: Either<Error, Data> = someFunctionThatReturnsEitherWrappedInIO().bind()
    val ansB: Either<Error, OtherData> = someOtherFunctionThatReturnsEitherWrappedInIO().bind()

    val newData: Either<Any, NewData> = Either.monad<Any>().binding {
        val data: Data = ans.bind()
        val otherData: OtherData = ansB.bind()
        NewData(data.a, otherData.lala)
    }.fix()
}

Solution

  • Background

    First I should mention that Monads don't compose, that's why you need a Monad transformer, in your case EitherT is the guy that can help you.

    Example

    object Error
    
    fun one() = IO { Right(1) }
    fun two() = IO { Right("2") }
    fun toInt(str: String) = IO { Try { str.toInt() }.toEither { Error } }
    
    val result: IO<Either<Error, Int>> =
        EitherT.monad<ForIO, Error>(IO.monad()).binding {
            val oneInt = EitherT(one()).bind()
            val twoString = EitherT(two()).bind()
            val twoInt = EitherT(toInt(twoString)).bind()
            oneInt + twoInt
        }.value().fix()
    
    println(result.unsafeRunSync()) // Just for demonstration, don't do this ever
    

    Right(b=3)