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


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

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


8636
2017-09-10 20:05


起源



答案:


有两个monad是不够的(为 M并且绰绰有余(for 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不再提供必要的 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))

无需额外打字。


14
2017-09-10 20:25



在使用Scalaz 7的REPL中,它失败了,因为它找不到Seq的Traverse类型类实例。也许我应该导入其他东西? - Nikita Volkov
您可以使用 List 代替 Seq,或提供您自己的实例 Seq - 我不知道为什么 Seq 实例在7中消失了。 - Travis Brown
谢谢,让它工作!但我对它的行为感到沮丧:除了 Seq 问题还有一个要求你明确指定类型: val xs = List(Some(1), Some(45)); (xs : List[Option[Int]]).sequence - Nikita Volkov
@NikitaVolkov:查看我的更新。 - Travis Brown
再次感谢。大! - Nikita Volkov


答案:


有两个monad是不够的(为 M并且绰绰有余(for 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不再提供必要的 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))

无需额外打字。


14
2017-09-10 20:25



在使用Scalaz 7的REPL中,它失败了,因为它找不到Seq的Traverse类型类实例。也许我应该导入其他东西? - Nikita Volkov
您可以使用 List 代替 Seq,或提供您自己的实例 Seq - 我不知道为什么 Seq 实例在7中消失了。 - Travis Brown
谢谢,让它工作!但我对它的行为感到沮丧:除了 Seq 问题还有一个要求你明确指定类型: val xs = List(Some(1), Some(45)); (xs : List[Option[Int]]).sequence - Nikita Volkov
@NikitaVolkov:查看我的更新。 - Travis Brown
再次感谢。大! - Nikita Volkov