【问题标题】:How to convert A[B[C]] to B[A[C]] if A and B are monads?如果 A 和 B 是单子,如何将 A[B[C]] 转换为 B[A[C]]?
【发布时间】:2012-09-03 17:34:00
【问题描述】:

我正在寻找一种更通用的解决方案,该解决方案利用 monads(可能还有 monoids)来实现与 if( xs.contains(None) ) None else Some(xs.flatten) 适用于 xs 类型的 Seq[Option[A]]

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

【问题讨论】:

    标签: scala monads scalaz


    【解决方案1】:

    拥有两个 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]],而我们没有SomeApplicative 实例。

    Scalaz 提供了一个方便的 some 方法,其工作方式与 Some.apply 类似,但为您提供了已经输入为 Option 的内容,因此您可以编写以下代码:

    scala> List(some(1), some(45)).sequence
    res1: Option[List[Int]] = Some(List(1, 45))
    

    无需额外输入。

    【讨论】:

    • 在带有 Scalaz 7 的 REPL 中它失败了,因为它找不到 Seq 的 Traverse 类型类实例。也许我应该导入其他东西?
    • 你可以使用List而不是Seq,或者为Seq提供你自己的实例——我不知道为什么Seq实例在7中消失了。
    • 谢谢,成功了!但我对其行为感到沮丧:除了Seq 问题之外,还有另一个问题要求您明确指定类型:val xs = List(Some(1), Some(45)); (xs : List[Option[Int]]).sequence
    猜你喜欢
    • 1970-01-01
    • 2011-05-30
    • 2021-12-27
    • 2017-01-05
    • 2014-03-23
    • 1970-01-01
    • 2020-07-15
    • 2011-08-01
    • 1970-01-01
    相关资源
    最近更新 更多