免费monad比使用IO monads的普通旧特性有什么优势?

时间:2017-10-16 08:42:26

标签: scala error-handling functional-programming traits free-monad

所以我一直在深入研究FP概念,我喜欢封装在IO monad中的纯度概念。然后我读了this,并认为IO monad确实不像使用Free Monads那样解耦(?)。

所以我开始使用这些概念完成我的工作,然后我意识到traits实现了将结构与执行分离的相同目的。更糟糕的是,使用免费monad有很多限制,比如错误处理和将上下文边界和隐式参数传递到解释器/实现中。

所以我的问题是:使用它们有什么好处?如何解决我刚才提到的问题(隐式参数和错误处理)?免费Monands的使用是否限制在学术领域,还是可以在行业中使用?

编辑:解释我的疑惑的一个例子

  import cats.free.Free._
  import cats.free.Free
  import cats.{Id, ~>}

  import scala.concurrent.Future

  sealed trait AppOpF[+A]

  case class Put[T](key: String, value: T) extends AppOpF[Unit]

  case class Delete(key: String) extends AppOpF[Unit]
  //I purposely had this extend AppOpF[T] and not AppOpF[Option[T]]
  case class Get[T](key: String) extends AppOpF[T]

  object AppOpF {
    type AppOp[T] = Free[AppOpF, T]

    def put[T](key: String, value: T): AppOp[Unit] = liftF[AppOpF, Unit](Put(key, value))

    def delete(key: String): AppOp[Unit] = liftF[AppOpF, Unit](Delete(key))

    def get[T](key: String): AppOp[T] = liftF[AppOpF, T](Get(key))

    def update[T](key: String, func: T => T): Free[AppOpF, Unit] = for {
      //How do I manage the error here, if there's nothing saved in that key?
      t <- get[T](key)
      _ <- put[T](key, func(t))
    } yield ()


  }

  object AppOpInterpreter1 extends (AppOpF ~> Id) {
    override def apply[A](fa: AppOpF[A]) = {
      fa match {
        case Put(key,value)=>
          ???
        case Delete(key)=>
          ???
        case Get(key) =>
          ???
      }
    }
  }
  //Another implementation, with a different context monad, ok, that's good
  object AppOpInterpreter2 extends (AppOpF ~> Future) {
    override def apply[A](fa: AppOpF[A]) = {
      fa match {
        case a@Put(key,value)=>
          //What if I need a Json Writes or a ClassTag here??
          ???
        case a@Delete(key)=>
          ???
        case a@Get(key) =>
          ???
      }
    }
  }

1 个答案:

答案 0 :(得分:0)

带有IO monad的自由代数具有相同的目的-将程序构建为纯数据结构。如果将Free与IO的某些具体实现进行比较,则IO可能会获胜。它具有更多功能和特殊特征,可帮助您快速移动并快速开发程序。但这也意味着您将在某个IO实现上拥有主要的供应商锁定。无论您选择哪种IO,它都将是一个具体的IO库,它可能存在性能问题,错误或支持问题-谁知道。由于您的程序和实施之间的紧密联系,将您的程序从一个供应商更改为另一个供应商会花费很多钱。

另一方面,自由代数允许您表达程序而无需谈论程序的实现。它以一种既可以轻松测试又可以独立更改的方式将您的需求与实现分开。另一个好处是,Free允许您根本不使用IO。您可以在其中包装标准的Futures,Java的标准CompletableFuture或任何其他第三方并发原语,您的程序仍将是纯净的。为此,Free将需要额外的样板(就像您在示例中所展示的),并且灵活性较低。所以选择的是你的。

还有另一种方法-最终无标签。这是一种试图从双方平衡专业人士的方法,以减少供应商的锁定,但仍不像自由代数那样冗长。值得一试。