我正在寻求一种更通用的解决方案,利用单子(可能是幺半群)来实现与if( xs.contains(None) ) None else Some(xs.flatten)
相同的结果,对于类型为Seq[Option[A]]
的xs
。
如何使用Scalaz实现这个功能?我觉得我漏掉了一些明显的东西。
对于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 不再为 Seq
提供必要的 Traverse
实例(尽管您可以很容易地编写自己的实现)。
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]]
,而我们没有 Some
的 Applicative
实例。some
方法,它的作用与 Some.apply
相似,但是可以直接获得一个已经被定义为 Option
类型的值,因此你可以这样写:scala> List(some(1), some(45)).sequence
res1: Option[List[Int]] = Some(List(1, 45))
无需额外输入。
List
替代Seq
,或者为Seq
提供自己的实例 - 我不确定为什么Seq
实例在 7 中消失了。 - Travis BrownSeq
问题之外,还有另一个需要您明确指定类型的问题:val xs = List(Some(1), Some(45)); (xs : List[Option[Int]]).sequence
- Nikita Volkov