我正在寻找一种更通用的解决方案,它利用monad(和可能的monoid)来实现相同的效果
if( xs.contains(None) ) None else Some(xs.flatten)
适用于xs
类型的Seq[Option[A]]
。
我如何使用Scalaz做到这一点?我觉得我错过了一些明显的东西。
答案 0 :(得分:14)
拥有两个monad是不够的(对于M
)而且绰绰有余(对于N
) - 当然加起来还不够 - 但如果M
有一个Traverse
实例和N
有Applicative
个实例,您可以使用sequence
。例如:
import scalaz._, Scalaz._
def foo[A](xs: List[Option[A]]): Option[List[A]] = xs.sequence
这具有您想要的语义。请注意,我使用的是List
而不是Seq
,因为Scalaz 7不再为Traverse
提供必要的Seq
实例(尽管您可以轻松编写自己的实例)。
正如您所注意到的,以下内容无法编译:
List(Some(1), Some(45)).sequence
虽然你可以在那里抛出None
,但没关系:
scala> List(Some(1), None, Some(45)).sequence
res0: Option[List[Int]] = None
这是因为List(Some(1), Some(45))
的推断类型为List[Some[Int]]
,而Applicative
我们没有Some
个实例。
Scalaz提供了一个方便的some
方法,其工作方式与Some.apply
类似,但为您提供了已经输入为Option
的内容,因此您可以编写以下内容:
scala> List(some(1), some(45)).sequence
res1: Option[List[Int]] = Some(List(1, 45))
无需额外打字。