【问题标题】:Idiomatic way to combine different monads with for in Scala在 Scala 中将不同 monad 与 for 组合的惯用方式
【发布时间】:2014-09-19 19:56:59
【问题描述】:

假设我们有两个值包装在不同的 monad 中(例如 Try 和 Option):

val x: Option[Int] = Some(10)
val y: Try[Int] = Success(4)

我们希望得到这些值的总和。一个人会写

val z = for {
  xval <- x
  yval <- y
} yield xval + yval

但由于类型错误,它不会被编译。有没有一种惯用的 Scala 方式来处理这个问题?

【问题讨论】:

  • Monads generally are not composable/combinable,但使用 Try 你可以使用 .toOption
  • 你也不会真正在 Haskell 中组合 monad,你只会将它们全部堆叠起来,创建越来越深的嵌套
  • Monad 不可组合,寻找 Monad 转换器,例如 TryT[Option, A]

标签: scala


【解决方案1】:

Scala 标准库缺少一些有用的函数/抽象,但幸运的是,有一个名为 Scalaz 的补充库可提供您所需的大部分功能。

特别是,正如建议的那样,您正在寻找 Monad 转换器。请参阅以下两个帖子:

http://eed3si9n.com/learning-scalaz/Monad+transformers.html

http://underscoreconsulting.com/blog/posts/2013/12/20/scalaz-monad-transformers.html

【讨论】:

    【解决方案2】:

    使用Cats monad 转换器OptionT:

    val z = (for {
       xval <- OptionT.fromOption(x): OptionT[Try, Int]
       yval <- OptionT.liftF(y)
    } yield xval + yval).value
    

    但是,返回类型是Try[Option[Int]]

    【讨论】:

      【解决方案3】:

      Daniel Spiewak 的 Emm 库能够组合多个单子,但由于它不遵守所有单子定律,因此该库仅用于教学目的。

      Emm Github:https://github.com/djspiewak/emm

      Daniel 就 Emm 做了一个演示:https://www.youtube.com/watch?v=E5Tri3Yow0U

      我还遇到过 FreeK,一个用于编写多个 Free monad 的库:https://github.com/ProjectSeptemberInc/freek

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-01-23
        • 1970-01-01
        • 2014-03-06
        • 2012-04-02
        • 1970-01-01
        • 2011-06-16
        • 1970-01-01
        相关资源
        最近更新 更多