scalascala-catskleisli

List of Kleisli to Kleisli of list


I was wondering if there is a way to turn List[Kleisli[Option, Int, Int]] to Kleisli[Option, Int, List[Int]].

In particular I have the list of kleisli formed like this:

def k(a: String) = Kleisli[Option, Int, Int](m => Some(a.length * m))
val kList = List("hi", "hello").map(k)

What I do is the following

Kleisli[Option, Int, List[Int]](m => kList.map(_.run(m)).sequence)

which is very messy, not expressive and requires a lot of manual work.

Is there a better way?


Solution

  • Yes, you can use traverse which does just that. If you're using cats <= 0.9.0 you can use the following code:

    import cats.data._
    import cats.instances.list._
    import cats.instances.option._
    import cats.syntax.traverse._
    
    // ...
    def k(a: String) = Kleisli[Option, Int, Int](m => Some(a.length * m))
    val result: Kleisli[Option, Int, List[Int] = List("hi", "hello").traverseU(k)
    

    If you're using Scala 2.11.9+, by adding scalacOptions += "-Ypartial-unification" to your build.sbt file, you can just use traverse in place of traverseU. Also, starting from version 1.0.0, traverseU and sequenceU will no longer exist.

    Note that, if you're using Scala < 2.11.9 but >= 2.10.6 you can still enable partial unification by adding this plugin to your build.