我写了一个例子来使用 scalaz.Free 来将 Action 映射到 Future,它看起来很酷。但是,我试图了解它的好处。我希望我能在这里得到答案。这是我的代码片段
首先,我创建了一个 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)
它似乎有效,我想我理解这个单子和解释器的东西。但是,我在想如果我直接使用Future.flatmap和map与解决方案相比有什么好处?
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。如果是这样,有人可以给我更具体的例子,所以我可以看到好处吗?
提前致谢