Possiedo un'app che esegue molte chiamate a diversi sistemi di back-end e che spera di utilizzare le incomprensioni per semplificare il flusso di processo attraverso i sistemi di back-end.Combinazione di EitherT e Future
Sto cercando di combinare EitherT (scalaz) e Future (scala 2.10) in modo da poter acquisire il primo errore potenziale (in cui è un problema di sistema futuro o back-end) e restituire un messaggio appropriato all'utente finale. Ho avuto una rapida occhiata a Validation scalaz ma la raccomandazione per catturare il primo errore e non tutti gli errori è usare EitherT.
Sto cercando un semplice esempio in REPL prima, però sto ottenendo il seguente errore
errore: non riusciva a trovare valore implicito per il parametro F: scalaz.Functor [scala.concurrent.Future]
import scala.concurrent._
import scalaz._
import Scalaz._
import ExecutionContext.Implicits.global
type EitherFuture[+A] = EitherT[Future, String, A]
def method1Success : EitherFuture[Int] = {
println("method 1 success")
EitherT {
Future {
1.right
}
}
}
def method2Failure : EitherFuture[Int] = {
println("method 2 failure")
EitherT {
Future {
"fail".left
}
}
}
val m1 = method1Success
// problem
m1.isRight
// problem
def methodChain1 = {
for {
a <- method1Success
b <- method2Failure
} yield b
}
Sono ancora nuovo su scala e scalaz quindi qualsiasi suggerimento sarebbe ottimo.
** Aggiornamento **
Includendo scalaz-contrib basata su suggerimento @stew ora ho una versione aggiornata che mostra per-comprensioni con la Combined EitherT e futuro che mostra diverse utilizzare semplici casi di successo backend, un backend fallimento, e di un futuro fallimento
import scala.concurrent._
import scalaz._
import Scalaz._
import ExecutionContext.Implicits.global
import scalaz.contrib._
import scalaz.contrib.std._
import scala.concurrent.duration._
type EitherFuture[+A] = EitherT[Future, String, A]
// various methods that mimic success or different failures
def methodBackendSuccess : EitherFuture[Int] = {
println("method backend success")
EitherT {
Future {1.right}
}
}
def methodBackendFailure : EitherFuture[Int] = {
println("method backend failure")
EitherT {
Future { "fail".left}
}
}
def methodFutureFailure : EitherFuture[Int] = {
println("method future failure")
EitherT {
Future.failed(new Exception("future failed"))
}
}
// different combinations for for-comprehensions
def methodChainBackendSuccess = {
for {
a <- methodBackendSuccess
b <- methodBackendSuccess
c <- methodBackendSuccess
} yield c
}
def methodChainBackendFailure = {
for {
a <- methodBackendSuccess
b <- methodBackendFailure
c <- methodBackendSuccess
} yield c
}
def methodChainFutureFailure = {
for {
a <- methodBackendSuccess
b <- methodFutureFailure
c <- methodBackendSuccess
} yield c
}
// process results for different chain methods
def processOutcome(chainMethod: => EitherFuture[Int]):Int = try {
val x = Await.result(chainMethod.run, 30 seconds)
x.toEither match {
case Left(l) => {
println("Backend failure <" + l + ">")
-1
}
case Right(r) => {
println("Backend success <" + r + ">")
r
}
}
} catch {
case e: Exception => {
println("Future error <" + e.getMessage + ">")
-99
}
}
// run tests
val backendSuccess = processOutcome(methodChainBackendSuccess)
val backendFailure = processOutcome(methodChainBackendFailure)
val futureFailure = processOutcome(methodChainFutureFailure)
Sei sicuro di aver bisogno del business "oither"? 'Future' può già modellare il fallimento e il sequenziamento ha il comportamento che si desidera. –
Ciao @TravisBrown Mi sto ancora muovendo per la scala, quindi potresti avere quello che mi serve è la capacità di catturare un back-end di successo, un back-end e un futuro fallimento e gestirli diversamente. Ora ho un codice che funziona, aggiornerò la domanda originale e forse questo potrebbe chiarire se ho bisogno di un EitherT e Future combinato o meno. –
Una cosa che mi ha portato un po 'di tempo: Functor [Future] può essere trovato solo se un contesto di esecuzione implicito è nello scope – cvogt