【发布时间】:2017-01-08 18:09:32
【问题描述】:
在Integrating State with Either(幻灯片88)中,鉴于State 的模式在Either 下分层,是否有推荐的方法来添加另一种类型的状态,例如,通过Writer 之类的方式进行日志记录?似乎新状态必须存在于现有 State 和 Either 之间,以便利用 flatMap 中 Either 的快速失败行为。
以下是演示文稿中代码的可运行示例,经过调整后可在 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