我正在寻找一种更通用的解决方案,它利用 monads(可能还有 monoids)来实现与
if( xs.contains(None) ) None else Some(xs.flatten)
for xs
of type相同的效果Seq[Option[A]]
。
我怎么能用 Scalaz 做到这一点?我觉得我错过了一些明显的东西。
有两个 monad 是不够的 (for M
) 和绰绰有余的 (for 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))
无需额外输入。