如果A和B是单子,如何将A [B [C]]转换为B [A [C]]?

时间:2012-09-10 20:05:50

标签: scala monads scalaz

我正在寻找一种更通用的解决方案,它利用monad(和可能的monoid)来实现相同的效果 if( xs.contains(None) ) None else Some(xs.flatten)适用于xs类型的Seq[Option[A]]

我如何使用Scalaz做到这一点?我觉得我错过了一些明显的东西。

1 个答案:

答案 0 :(得分:14)

拥有两个monad是不够的(对于M)而且绰绰有余(对于N) - 当然加起来还不够 - 但如果M有一个Traverse实例和NApplicative个实例,您可以使用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))

无需额外打字。