Reputation: 1588
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.
Upvotes: 2
Views: 198
Reputation: 139038
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.
Upvotes: 5