I want to transform a List[Option[T]]
into a Option[List[T]]
. The signature type of the function is
def lo2ol[T](lo: List[Option[T]]): Option[List[T]]
The expected behavior is to map a list that contains only Some
s into a Some
containing a list of the elements inside the elements Some
's. On the other hand, if the input list has at least one None
, the expected behavior is to just return None
. For example:
scala> lo2ol(Some(1) :: Some(2) :: Nil) res10: Option[List[Int]] = Some(List(1, 2)) scala> lo2ol(Some(1) :: None :: Some(2) :: Nil) res11: Option[List[Int]] = None scala> lo2ol(Nil : List[Option[Int]]) res12: Option[List[Int]] = Some(List())
An example implementation, without scalaz, would be:
def lo2ol[T](lo: List[Option[T]]): Option[List[T]] = { lo.foldRight[Option[List[T]]](Some(Nil)){(o, ol) => (o, ol) match { case (Some(x), Some(xs)) => Some(x :: xs); case _ => None : Option[List[T]]; }}}
I remember seeing somewhere a similar example, but using Scalaz to simplify the code. How would it look like?
A slightly more succinct version, using Scala2.8 PartialFunction.condOpt
, but still without Scalaz:
import PartialFunction._ def lo2ol[T](lo: List[Option[T]]): Option[List[T]] = { lo.foldRight[Option[List[T]]](Some(Nil)){(o, ol) => condOpt(o, ol) { case (Some(x), Some(xs)) => x :: xs } }}
There's a function that turns a List[Option[A]]
into an Option[List[A]]
in Scalaz. It's sequence
. To get None
in case any of the elements are None
and a Some[List[A]]
in case all the elements are Some
, you can just do this:
import scalaz.syntax.traverse._ import scalaz.std.list._ import scalaz.std.option._ lo.sequence
This method actually turns F[G[A]
into G[F[A]]
given that there exists an implementation of Traverse[F]
, and of Applicative[G]
(Option
and List
happen to satisfy both and are provided by those imports).
The semantics of Applicative[Option]
are such that if any of the elements of a List
of Option
s are None
, then the sequence
will be None
as well. If you want to get a list of all the Some
values regardless of whether any other values are None
, you can do this:
lo flatMap (_.toList)
You can generalize that for any Monad
that also forms a Monoid
(List
happens to be one of these):
import scalaz.syntax.monad._ def somes[F[_],A](x: F[Option[A]]) (implicit m: Monad[F], z: Monoid[F[A]]) = x flatMap (o => o.fold(_.pure[F])(z.zero))
For some reason you dislike
if (lo.exists(_ isEmpty)) None else Some(lo.map(_.get))
? That's probably the shortest in Scala without Scalaz.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With