【问题标题】:Layering State with Either in scalaz在 scalaz 中使用 Either 分层状态
【发布时间】:2017-01-08 18:09:32
【问题描述】:

Integrating State with Either(幻灯片88)中,鉴于State 的模式在Either 下分层,是否有推荐的方法来添加另一种类型的状态,例如,通过Writer 之类的方式进行日志记录?似乎新状态必须存在于现有 StateEither 之间,以便利用 flatMapEither 的快速失败行为。

以下是演示文稿中代码的可运行示例,经过调整后可在 Scalaz 7.2.8 上运行 2.11.8。有没有一种方法可以在现有行为之上干净地添加新的 monad 转换器,从而简化重构? Stacking StateT in Scalaz 适用于堆叠,但不处理由 Either 的快速失败 flatMap 行为造成的排序问题。

// 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())
}

【问题讨论】:

    标签: scala scalaz monad-transformers state-monad either


    【解决方案1】:

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

    object LayeringReaderWriterStateWithEither {
      // 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._
    
        type QueryStateS[A] = ReaderWriterState[List[String], String, 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 log(msg: String): QueryStateES[Unit] = liftS {
            ReaderWriterState[List[String], String, QueryState, Unit] {
              case (r, s) => (msg.format(r, s), (), s).point[Id]
            }
          }
        }
    
        def runQuery(s: String, m: Model): QueryStateES[QueryResult] = for {
          _ ← log("Starting")
          query <- parseQuery(s)
          _ ← log(s"Got a query: $query")
          res <- performQuery(query, m)
        } yield res
    
        def log(msg: String): QueryStateES[Unit] =
          QueryStateES.log(msg)
    
        def parseQuery(s: String): QueryStateES[StatsQuery] =
          QueryStateES.liftE(new Exception(s"TODO parse $s").left)
    
        def performQuery(q: StatsQuery, m: Model): QueryStateES[QueryResult] =
          QueryStateES.liftE(new Exception(s"TODO perform $q in $m").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(Nil, QueryState())
      }
    }
    

    【讨论】:

    • 解决方案是否可以推广到其他状态,例如提供历史/撤消等的状态?
    • 恐怕我不明白(我的错)。您是在问是否可以在做后撤消某些事情,我是传统的撤消意义?
    • 我只是在谈论“拦截器”的任意分层,它可能会影响状态,同时保持返回类型相同。可以发出back(3) 的“历史”拦截器只是一个例子。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-18
    • 1970-01-01
    • 2011-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多