免费Monad翻译

时间:2018-01-29 15:05:05

标签: scala monads scala-cats

我正在跟随Chris Myers谈论Free Monads,但是当我实现解释器时,我得到了编译错误

package object example {
  import cats._
  import cats.data._
  import cats.free._
  import cats.implicits._

  case class Property(Id: Int, post: String)

  type Script[A] = Free[AppAction, A]

  sealed trait AppAction[A] {
    def lift: Script[A] = Free.liftF(this)
  }

  case class FetchById(propertyId: Int) extends AppAction[Property]

  case class Save(property: Property) extends AppAction[Unit]

  case class Log(message: String) extends AppAction[Unit]

  def fetchById(id: Int): Script[Property] = FetchById(id).lift
  def save(property: Property): Script[Unit] = Save(property).lift

  def log(message: String): Script[Unit] = Log(message).lift


  def updatePost(propertyId: Int, post: String): Script[Property] = {
    for {
      property <- fetchById(propertyId)
      p1 = property.copy(post = post)
      _ <- log("Updating")
      _ <- save(p1)
    } yield p1
  }

  object TestInterp extends (AppAction ~> Id) {
    def apply[A](fa: AppAction[A]): Id[A] = fa match {
      case FetchById(_) => Property(1, "2000")
      case Save(_) => ()
      case Log(msg) => println(msg)
    }

    def run[A](script: Script[A]) = script.foldMap(this)
  }

}

我已经导入了猫,特别是cats.Id但我在我的测试解释器中得到了“类型属性的表达式不符合cats.Id”。我甚至在Id monad中明确地包装了fetchById的结果,但它没有用。

1 个答案:

答案 0 :(得分:2)

for - 表达式

p1 <- property.copy(post = post)

不是monadic绑定步骤。它就像定义辅助变量p1一样简单。这似乎有效:

import cats._
import cats.data._
import cats.free._
import cats.implicits._

case class Property(id: Int, post: String)


sealed trait AppAction[A] {
  def lift: Script[A] = Free.liftF(this)
}
case class FetchById(propertyId: Int) extends AppAction[Property]
case class Save(property: Property) extends AppAction[Unit]
case class Log(message: String) extends AppAction[Unit]

type Script[A] = Free[AppAction, A]

def fetchById(id: Int): Script[Property] = FetchById(id).lift
def save(property: Property): Script[Unit] = Save(property).lift
def log(message: String): Script[Unit] = Log(message).lift

def updatePost(propertyId: Int, post: String): Script[Unit] = {
  for {
    property <- fetchById(propertyId)
    p1 = property.copy(post = post)
    _ <- log("Updating")
    _ <- save(p1)
  } yield()
}

object TestInterp extends (AppAction ~> Id) {
  def apply[A](fa: AppAction[A]): Id[A] = fa match {
    case FetchById(_) => Property(1, "2000")
    case Save(_) => ()
    case Log(msg) => println(msg)
  }

  def run[A](script: Script[A]) = script.foldMap(this)
}