在scalaz中分层状态

Sim*_*Sim 20 scala state-monad monad-transformers either scalaz

将状态与Either进行整合(幻灯片88)时,给定State分层下的模式Either,是否有建议的方法来添加另一种类型的状态,例如,通过类似的方式记录Writer?看来新的国家有现有之间的生活StateEither为了利用快速失败行为EitherflatMap.

下面是演示代码的可运行示例,调整为使用Scalaz 7.2.8在2.11.8上工作.有没有一种方法可以在现有行为的基础上干净地添加新的monad变换器,简化了重构?在Scalaz中堆叠StateT适用于堆叠,但不处理由故障快速flatMap行为创建的排序问题Either.

// Based on slide 88+ in https://speakerdeck.com/mpilquist/scalaz-state-monad
// Adjusted for Scala 2.11 (invariant A), Scalaz 7.2 (Pointed->Applicative) and Throwable on lhs of Either
object IntegratingStateAndEither {
  import scalaz._
  import scalaz.Scalaz._
  import EitherT._
  import scalaz.StateT.stateMonad

  type QueryStateS[A] = State[QueryState, A]
  type ET[F[_], A] = EitherT[F, Throwable, A]
  type QueryStateES[A] = ET[QueryStateS, A]

  object QueryStateES {
    def apply[A](s: QueryStateS[Throwable \/ A]): QueryStateES[A] = EitherT(s)
    def liftE[A](e: Throwable \/ A): QueryStateES[A] = apply(Applicative[QueryStateS].point(e))
    def liftS[A](s: QueryStateS[A]): QueryStateES[A] = MonadTrans[ET].liftM(s)
  }

  def runQuery(s: String, m: Model): QueryStateES[QueryResult] = for {
    query <- parseQuery(s)
    res <- performQuery(query, m)
  } yield res

  def parseQuery(s: String): QueryStateES[StatsQuery] =
    QueryStateES.liftE(new Exception("TODO parse").left)

  def performQuery(q: StatsQuery, m: Model): QueryStateES[QueryResult] =
    QueryStateES.liftE(new Exception("TODO perform").left)

  // Just examples that do nothing
  case class Model()
  case class StatsQuery()
  case class QueryResult()
  case class QueryState()

  def test = runQuery("a + b", Model()).run.run(QueryState())
}
Run Code Online (Sandbox Code Playgroud)

Cha*_*ton 1

要回答有关日志记录的具体示例,您可以执行以下操作:

\n\n
object LayeringReaderWriterStateWithEither {\n  // Based on slide 88+ in https://speakerdeck.com/mpilquist/scalaz-state-monad\n  // Adjusted for Scala 2.11 (invariant A), Scalaz 7.2 (Pointed->Applicative) and Throwable on lhs of Either\n  object IntegratingStateAndEither {\n    import scalaz._\n    import scalaz.Scalaz._\n    import EitherT._\n\n    type QueryStateS[A] = ReaderWriterState[List[String], String, QueryState, A]\n    type ET[F[_], A] = EitherT[F, Throwable, A]\n    type QueryStateES[A] = ET[QueryStateS, A]\n\n    object QueryStateES {\n      def apply[A](s: QueryStateS[Throwable \\/ A]): QueryStateES[A] = EitherT(s)\n      def liftE[A](e: Throwable \\/ A): QueryStateES[A] = apply(Applicative[QueryStateS].point(e))\n      def liftS[A](s: QueryStateS[A]): QueryStateES[A] = MonadTrans[ET].liftM(s)\n      def log(msg: String): QueryStateES[Unit] = liftS {\n        ReaderWriterState[List[String], String, QueryState, Unit] {\n          case (r, s) => (msg.format(r, s), (), s).point[Id]\n        }\n      }\n    }\n\n    def runQuery(s: String, m: Model): QueryStateES[QueryResult] = for {\n      _ \xe2\x86\x90 log("Starting")\n      query <- parseQuery(s)\n      _ \xe2\x86\x90 log(s"Got a query: $query")\n      res <- performQuery(query, m)\n    } yield res\n\n    def log(msg: String): QueryStateES[Unit] =\n      QueryStateES.log(msg)\n\n    def parseQuery(s: String): QueryStateES[StatsQuery] =\n      QueryStateES.liftE(new Exception(s"TODO parse $s").left)\n\n    def performQuery(q: StatsQuery, m: Model): QueryStateES[QueryResult] =\n      QueryStateES.liftE(new Exception(s"TODO perform $q in $m").left)\n\n    // Just examples that do nothing\n    case class Model()\n    case class StatsQuery()\n    case class QueryResult()\n    case class QueryState()\n\n    def test = runQuery("a + b", Model()).run.run(Nil, QueryState())\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n