使用Scalaz将选项列表转换为列表选项 [英] Convert a List of Options to an Option of List using Scalaz

查看:66
本文介绍了使用Scalaz将选项列表转换为列表选项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将List[Option[T]]转换为Option[List[T]].该函数的签名类型为

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]]

预期的行为是将仅包含Some的列表映射到包含元素Some内的元素列表的Some中.另一方面,如果输入列表中至少有一个None,则预期的行为是仅返回None.例如:

The expected behavior is to map a list that contains only Somes 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())

不带scalaz的示例实现为:

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]]; 
}}}

我记得在某个地方看到过类似的示例,但是使用Scalaz简化了代码.看起来如何?

I remember seeing somewhere a similar example, but using Scalaz to simplify the code. How would it look like?

使用Scala2.8 PartialFunction.condOpt的简洁版本,但仍然没有Scalaz:

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
  }
}}

推荐答案

在Scalaz中有一个函数可以将List[Option[A]]转换为Option[List[A]]. sequence.要在任何元素为None的情况下获取None而在所有元素为Some的情况下获取Some[List[A]],则可以执行以下操作:

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

给定存在Traverse[F]Applicative[G]的实现,此方法实际上将F[G[A]转换为G[F[A]](OptionList恰好满足了这两个要求,并由这些导入提供).

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).

Applicative[Option]的语义是,如果OptionList的任何元素是None,那么sequence也将是None.如果要获取所有Some值的列表,而不管是否有其他值是None,则可以执行以下操作:

The semantics of Applicative[Option] are such that if any of the elements of a List of Options 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)

您可以概括地说,对于也形成Monoid的任何Monad(List恰好是其中之一):

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))

这篇关于使用Scalaz将选项列表转换为列表选项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆