20
(スライド88)で、State
のパターンがEither
の下にあると、Writer
のような別のタイプの状態を追加することをお勧めしますか?フェール・ファーストの動作をEither
flatMap
に利用するには、新しい状態が既存のState
とEither
の間になければならないようです。スカラーズのいずれかで状態をレイヤー化
以下は、Scalaz 7.2.8で2.11.8で動作するように調整されたプレゼンテーションのコードの実行可能な例です。既存のビヘイビアの上に新しいモナドトランスを追加することができ、リファクタリングを簡素化する方法はありますか? Stacking StateT in Scalazはスタッキングに適用されますが、フェール・ファーストの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())
}
ソリューションは、他の州への一般化していが、例えば、歴史を提供1の/ etc、元に戻しますか? – Sim
私は理解できません(私の悪いこと)。私は伝統的なアンドゥーセンスだと思っていますか? –
私は、戻り値の型を同じに保ちながら状態に影響を与える可能性のある「インターセプタ」の任意のレイヤリングについて簡単に説明しています。 'back(3)'を発行できる "履歴"インターセプタは単なる一例です。 – Sim