【发布时间】:2012-09-03 17:34:00
【问题描述】:
我正在寻找一种更通用的解决方案,该解决方案利用 monads(可能还有 monoids)来实现与
if( xs.contains(None) ) None else Some(xs.flatten) 适用于 xs 类型的 Seq[Option[A]]。
如何使用 Scalaz 做到这一点?我觉得我错过了一些明显的东西。
【问题讨论】:
我正在寻找一种更通用的解决方案,该解决方案利用 monads(可能还有 monoids)来实现与
if( xs.contains(None) ) None else Some(xs.flatten) 适用于 xs 类型的 Seq[Option[A]]。
如何使用 Scalaz 做到这一点?我觉得我错过了一些明显的东西。
【问题讨论】:
拥有两个 monad 是不够的(对于 M)和绰绰有余(对于 N)——当然,这加起来还不够——但是如果 M 有一个 Traverse 实例和 @ 987654325@ 有一个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 实例。
Scalaz 提供了一个方便的 some 方法,其工作方式与 Some.apply 类似,但为您提供了已经输入为 Option 的内容,因此您可以编写以下代码:
scala> List(some(1), some(45)).sequence
res1: Option[List[Int]] = Some(List(1, 45))
无需额外输入。
【讨论】:
List而不是Seq,或者为Seq提供你自己的实例——我不知道为什么Seq实例在7中消失了。
Seq 问题之外,还有另一个问题要求您明确指定类型:val xs = List(Some(1), Some(45)); (xs : List[Option[Int]]).sequence