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

Nik*_*kov 12 monads scala scalaz

我在寻找它利用单子(和类群可能)更广泛的解决方案,实现同 if( xs.contains(None) ) None else Some(xs.flatten)做的xs类型Seq[Option[A]].

我怎么能用Scalaz做到这一点?我觉得我错过了一些明显的东西.

Tra*_*own 14

有两个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
Run Code Online (Sandbox Code Playgroud)

这有你想要的语义.请注意,我使用的是List代替Seq,因为Scalaz 7不再提供必要的Traverse实例Seq(尽管您可以轻松编写自己的实例).


正如您所注意到的,以下内容无法编译:

List(Some(1), Some(45)).sequence
Run Code Online (Sandbox Code Playgroud)

虽然你扔None在那里很好:

scala> List(Some(1), None, Some(45)).sequence
res0: Option[List[Int]] = None
Run Code Online (Sandbox Code Playgroud)

这是因为推断类型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))
Run Code Online (Sandbox Code Playgroud)

无需额外打字.