问题描述
我正在寻找一个更通用的解决方案,它利用 monads(可能还有 monoids)来实现与if( xs.contains(None) ) None else Some(xs.flatten)
为 Seq[Option[A]]
类型的 xs
做.
I'm looking for a more general solution which exploits monads (and monoids possibly) to achieve the same asif( xs.contains(None) ) None else Some(xs.flatten)
does for xs
of type Seq[Option[A]]
.
如何使用 Scalaz 做到这一点?我觉得我遗漏了一些明显的东西.
How can I do that with Scalaz? I feel like I'm missing something evident.
推荐答案
有两个 monad 是不够的(对于 M
)和已经足够了(对于 N
)——当然这还不够——但是如果 M
有一个 Traverse
实例并且 N
有一个 Applicative
> 例如,您可以使用 sequence
.例如:
Having two monads is both not enough (for M
) and more than enough (for N
)—which adds up to not enough, of course—but if M
has a Traverse
instance and N
has an Applicative
instance, you can use sequence
. For example:
import scalaz._, Scalaz._
def foo[A](xs: List[Option[A]]): Option[List[A]] = xs.sequence
这具有您想要的语义.请注意,我使用的是 List
而不是 Seq
,因为 Scalaz 7 不再为 Seq
提供必要的 Traverse
实例>(尽管您可以轻松编写自己的).
This has the semantics you want. Note that I'm using List
instead of Seq
, since Scalaz 7 no longer provides the necessary Traverse
instance for Seq
(although you could easily write your own).
如您所见,以下内容无法编译:
As you've noticed, the following won't compile:
List(Some(1), Some(45)).sequence
虽然如果你把 None
扔进去也没关系:
Although it's fine if you throw a None
in there:
scala> List(Some(1), None, Some(45)).sequence
res0: Option[List[Int]] = None
这是因为 List(Some(1), Some(45))
的推断类型将是 List[Some[Int]]
,而我们不Some
有一个 Applicative
实例.
This is because the inferred type of List(Some(1), Some(45))
will be List[Some[Int]]
, and we don't have an Applicative
instance for Some
.
Scalaz 提供了一个方便的 some
方法,它的工作方式与 Some.apply
类似,但为您提供了一些已经输入为 Option
的内容,因此您可以写如下:
Scalaz provides a handy some
method that works like Some.apply
but gives you something that's already typed as an Option
, so you can write the following:
scala> List(some(1), some(45)).sequence
res1: Option[List[Int]] = Some(List(1, 45))
无需额外输入.
这篇关于如果 A 和 B 是单子,如何将 A[B[C]] 转换为 B[A[C]]?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!