W Integrating State with Either (slajd 88), z uwzględnieniem wzoru State
ułożonego pod numerem Either
, czy istnieje zalecane podejście do dodawania innego rodzaju stanu, na przykład rejestrowanie przez coś podobnego do Writer
? Wygląda na to, że nowy stan musi żyć między istniejącymi State
i Either
, aby skorzystać z szybkiego działania polegającego na niepowodzeniu: Either
w flatMap
.Stan warstwowania przy użyciu skalowania
Poniżej znajduje się działający przykład kodu z prezentacji, przystosowany do pracy w wersji 2.11.8 z Scalaz 7.2.8. Czy istnieje podejście, które może czysto dodać nowy transformator monady do istniejącego zachowania, upraszczając refaktoryzację? Stacking StateT in Scalaz dotyczy układania w stosy, ale nie zajmuje się problemem związanym z zamówieniem utworzonym przez niepowodzenie flatMap
zachowanie się 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())
}
Czy rozwiązanie uogólnić do innych państw, na przykład taki, który dostarcza historia/cofnąć, etc? – Sim
Obawiam się, że nie rozumiem (moje złe). Czy pytasz, czy możliwe jest cofnięcie czegoś po wykonaniu, jestem tradycyjnym sensem? –
Po prostu mówię o arbitralnym nakładaniu warstw "przechwytujących", które mogą wpływać na stan przy zachowaniu tego samego typu zwrotu. Przechwytywacz "historii", w którym można wydać 'powrót (3)' jest tylko jednym przykładem. – Sim