How to convert A[B[C]] to B[A[C]] if A and B are monads?
Solution 1:
Having two monads is both not enough (for M
) and more than enough (for N
)—which adds up to not enough, of course—but if M
has a Traverse
instance and N
has an Applicative
instance, you can use sequence
. For example:
import scalaz._, Scalaz._
def foo[A](xs: List[Option[A]]): Option[List[A]] = xs.sequence
This has the semantics you want. Note that I'm using List
instead of Seq
, since Scalaz 7 no longer provides the necessary Traverse
instance for Seq
(although you could easily write your own).
As you've noticed, the following won't compile:
List(Some(1), Some(45)).sequence
Although it's fine if you throw a None
in there:
scala> List(Some(1), None, Some(45)).sequence
res0: Option[List[Int]] = None
This is because the inferred type of List(Some(1), Some(45))
will be List[Some[Int]]
, and we don't have an Applicative
instance for Some
.
Scalaz provides a handy some
method that works like Some.apply
but gives you something that's already typed as an Option
, so you can write the following:
scala> List(some(1), some(45)).sequence
res1: Option[List[Int]] = Some(List(1, 45))
No extra typing necessary.