Question

I'm trying to achieve something like the following, where a and b are both intended to be of type Option[List[Int]]:

val a = List(1, 2, 3).some
val b = for {
  xs <- a
  el <- xs
} yield el + 1

Of course, this doesn't work because it's translated into

val b = a flatMap (xs => xs map (el => el + 1))

whereas I'm looking for

val b = a map (xs => xs map (el => el + 1))

In order to put this into a for comprehension, I have to nest them:

val b = for {
  xs <- a
} yield for {
  el <- xs
} yield el + 1

This last form works. Is there a way to get the same result using the first form? I feel like I've seen something along these lines using Kleisli composition or monad transformers but couldn't seem to find what I needed.

Was it helpful?

Solution

The ListT monad transformer in Scalaz is actually a little better than your first version (or at least more concise—you only have to worry about one layer):

import scalaz._, Scalaz._

val a = ListT(List(1, 2, 3).some)

val b = for { el <- a } yield el + 1

Or equivalently:

val b = a.map(_ + 1)

Here a and b are both instances of ListT[Option, Int]. You can unwrap these values and get a plain old Option[List[Int]] using underlying:

scala> b.underlying
res0: Option[List[Int]] = Some(List(2, 3, 4))

You can do lots of other things with ListT, like sequence functions from values into options of lists, etc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top