Search code examples
kotlinkotlin-coroutinesarrow-kt

Arrow-Kt Fx vs Kotlin Coroutines


I am trying to learn Arrow-Kt since I got curious about Functional Programming in Kotlin.

Can someone explain why there is a need to create another construct that functions almost similarly to Kotlin Coroutines? or am I wrong in my understanding of this?

How do these two tie in together?


Solution

  • NEW ANSWER

    This answer was already quite old, and was terribly outdated. Therefore I wanted to update this question, to reflect the current situation. At time of updating Arrow is version 1.1.2, but this will most likely not change anymore in the future.

    Arrow Fx used to implement its own runtime, but this caused a lot of friction with the existing eco-system that was build around KotlinX Coroutines. So instead of continuing our work on a custom runtime, we re-implemented all of Arrow Fx's APIs on top of KotlinX Coroutines with all the existing guarantees, and test suites passing. Effectively proofing that KotlinX Coroutines can support a functional effect system like we defined in Arrow Fx Coroutines.

    So now Arrow Fx builds entirely on-top of KotlinX Coroutines, and thus adheres to all of its principles such as Structured Concurrency.

    It does not longer have an IO type, but instead Arrow has changed it direction to fully support and embrace suspend () -> A (and suspend CoroutineScope.() -> A as we felt it was superior in both performance, and syntax.

    Since then Arrow has invested most of its efforts in building monadic DSLs that work nicely together with suspend, such that you can more easily create complex workflows and mix concerns of Either, suspend, etc without requiring complex abstractions, or difficult theory. For example:

    object MyError
    object User
    
    suspend fun fetchUser(): Either<MyError, User> =
        User.right()
    
    suspend fun example(): Either<MyError, List<User>> = either {
      delay(10_000) // suspending sleep
      (0..10).parTraverse(Dispatchers.IO) { // parallel map on IO
        user().bind() // get `User` out of Either<E, User>
      }
    }
    

    As you can see above we can easily combine the powers of parallelism, concurrency and monadic operations in a Kotlin idiomatic manner.

    So Arrow Fx and Kotlin/KotlinX Coroutines are now seemingly working together, and you can mix-and-match code however suits your needs.

    Arrow Fx aims to offer some higher level operators in addition to KotlinX Coroutines, and other Arrow libraries such as Arrow Core aim to complement the language and eco-system in the same manner.

    OLD POST

    Arrow fx uses coroutines when dealing with IO, doesn't replace them. Similar to how Room has extensions that allow to use Flow.

    That's incorrect, Arrow Fx builds a purely functional runtime library for Kotlin's suspend system. Just like KotlinX Coroutines builds runtime library for Kotlin's library.

    So both libraries offer an implementation for Kotlin's suspend system and can be used interchange-ably or independently depending on your needs or use-cases.

    Arrow Fx offers a purely functional lazy runtime for Kotlin’s suspend system with side-effect tracking and monad comprehensions (as shown by Pablisco).

    It contains an IO type, which is equivalent to suspend () -> A and has many powerful concurrency primitives like Semaphore, Queue, Ref, Promise, etc. They all guarantee resource safety, while offering powerful concurrent and parallel combinators and automatically cancellation support. (In the next version we'll also have support for suspend () -> Either<E, A>)

    In contrast to KotlinX Coroutines, which offers an eager implementation of Kotlin’s suspend system with cooperative cancellation support and a cold stream implementation.