【问题标题】:why we need Free monad to interpret Action to Future为什么我们需要 Free monad 来解释 Action 到 Future
【发布时间】:2015-12-13 09:33:12
【问题描述】:

我写了一个示例来使用 scalaz.Free 将 Action 映射到 Future,它看起来很酷。但是,我试图了解它的好处。我希望我能在这里得到答案。这是我的代码 sn-p

首先,我创建一个Action,即AST。

trait Action[A]

case class GetNumberAction(x: Int) extends Action[Int]
case class GetStringAction(x: String) extends Action[String]
case class ConvertToIntAction(x: String) extends Action[Int]
case class AddAction(x: Int, y: Int) extends Action[Int]

然后,我创建一个类,使用 Scalaz Free 和 Coyonda 将 Action 映射到 ASTMonad。

type Functor[A] = Coyoneda[Action, A]
type ASTMonad[A]= Free[Functor, A]

def toMonad[A](action: Action[A]): ASTMonad[A] = Free.liftFC[Action, A](action) 

object ADTMonad {
    def getNumber(x: Int): ASTMonad[Int] = toMonad(GetNumberAction(x))
    def getString(x: String): ASTMonad[String] = toMonad(GetStringAction(x))
    def converToInt(x: String): ASTMonad[Int] = toMonad(ConvertToIntAction(x))
    def add(x: Int, y: Int): ASTMonad[Int] = toMonad(AddAction(x, y))

}

最后,我创建了一个解释器来将 Action 解释为 Future

object Interpreter extends (Action ~> Future) {
    def apply[A](action: Action[A]): Future[A] = {
        action match {
            case GetNumberAction(x) => Future(x)
            case GetStringAction(x) => Future(x)
            case ConvertToIntAction(x) => Future(x.toInt)
            case AddAction(x, y) => Future(x + y)
        }
    }
}

当我运行它时,我可以使用

val chain =  for {
    number <- ASTMonad.getNumber(x)
    str <- ASTMonad.getString(y)
    convertedNumber <- ASTMonad.converToInt(str)
    total <- ASTMonad.add(number, convertedNumber)
    } yield total

chain.runWith(Interpreter)

它似乎有效,我想我理解这个 monad 和解释器的东西。但是,我在想如果我直接使用 Future.flatmapmap 与解决方案相比有什么好处?

for {
    number <- Future(x)
    str <- Future(y)
    convertedNumber <- Future(str.toInt)
    total <- Future(number + convertedNumber)
} yield total

使用 Future flatmap 和 map 的代码对我来说看起来更简单。那么回到我的问题,我们是否需要使用 Free monad 来将业务逻辑解释给 Future,因为 Future 已经提供了 flatMap 和 map。如果是这样,谁能给我更具体的例子,让我看到好处?

提前致谢

【问题讨论】:

    标签: scala scalaz free-monad


    【解决方案1】:

    使用免费应用程序的一个很好且有动机的例子是命令行解析器,我们将类型称为CLI[A]

    CLI[A] 类型的值意味着如果您提供命令行参数 (Array[String]) 并且可以成功解析它们,您将获得 A。现在,当使用Either 进行错误处理时,此功能与Array[String] -&gt; Either[String,A] 同构。

    因为您已将CLI 应用,您可以将mapapply(组合)值。例如,您可以创建一个Int 参数count,另一个Int 参数count2,并将它们组合成一个包含它们总和的最终sum: CLI[Int]

    假设您直接应用计算,这会产生“仅”相当于Array[String] -&gt; Either[String,Int] 的东西。但是如果你想创建一个帮助文本,你必须知道两个初始参数,而这些信息会丢失。

    Free 来救援。使用Free,您可以保留计算图,您可以使用它来提取直接从参数解析的所有初始CLI 值。然后,您可以稍后通过提供所有初始参数的解析结果来运行产生 sum 最终值的计算。

    当然,您可以实现一个特殊的 CLI 来跟踪计算中的所有初始值,但是 Free 让您避免这些额外的工作。

    【讨论】:

      猜你喜欢
      • 2017-03-12
      • 1970-01-01
      • 1970-01-01
      • 2016-03-14
      • 1970-01-01
      • 2019-06-09
      • 2010-12-18
      • 1970-01-01
      • 2011-06-19
      相关资源
      最近更新 更多