如果我有一个decoder_input= Input(shape_equal_to_encoder_output_shape)
decoder = Conv2D(32, (3, 3), activation='relu', padding='same')(decoder_input)
x = UpSampling2D((2, 2))(decoder)
x = Conv2D(32, (3, 3), activation='relu', padding='same')(x)
x = UpSampling2D((2, 2))(x)
decoded = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x)
decoder = Model(decoder_input, decoded)
表示可能的错误消息(auto_input = Input(shape=(28,28,1))
encoded = encoder(auto_input)
decoded = decoder(encoded)
auto_encoder = Model(auto_input, decoded)
)或成功的计算(Future[Either[String, Int]]
),则移动String
'很简单出现在左侧的错误消息:
Int
我希望Future
存在类似的东西,但是也许我只是找不到它叫什么。它相对简单,但是需要拆箱然后重新装箱,感觉很不舒服。
def handleFailure(fe: Future[Either[String,Int]]) =
f.recover({ case e: Exception => Left(s"failed because ${e.getMessage}"))
Cat确实在while ago中添加了一个EitherT
实例,但是它专门用于直接恢复到Either的def handleFailureT(fe: EitherT[Future, String, Int]) =
EitherT(handleFailure(et.value)) // See above for handleFailure definition
中,而不是替换Either本身。
MonadError
是否实现了Cats,如果这样,它叫什么名字?
答案 0 :(得分:3)
这一点都不明显,但是我认为这就是attempt
和attemptT
的目的。例如:
val myTry: Try[Int] = Try(2)
val myFuture: Future[String] = Future.failed(new Exception())
val myTryET: EitherT[Try, Throwable, Int] = myTry.attemptT
val myFutureET: EitherT[Future, Throwable, String] = myFuture.attemptT
// alternatively
val myFutureET: EitherT[Future, Throwable, String] = EitherT(myFuture.attempt)
有一个PR可以将其添加到文档中:https://github.com/typelevel/cats/pull/3178 -但是它目前没有出现在文档中。但是,您可以在这里看到它:https://github.com/typelevel/cats/blob/master/docs/src/main/tut/datatypes/eithert.md#from-applicativeerrorf-e-to-eithertf-e-a
答案 1 :(得分:0)
在此上花费了几个小时后,我可以肯定的是,截至2019年3月,此功能尚未直接在cat中实现。但是,已经存在的catsDataMonadErrorFForEitherT
monad确实可以以主要简单的方式实现它。
implicit class EitherTFutureAdditions[A, B](et: EitherT[Future, A, B]) {
val me = EitherT.catsDataMonadErrorFForEitherT[Future, Throwable, A]
def recoverLeft(pf: PartialFunction[Throwable, A]): EitherT[Future, A, B] =
me.recoverWith[B](et) { case t: Throwable =>
EitherT.fromEither[Future](Left(pf(t)))
}
}
我不确定在泛型隐式类中构造monad的性能含义如何,但它确实有效。如果您不需要一般情况,则可以将[A, B]
替换为显式类型。
我当时也写了recoverWithFlat
,handleErrorLeft
和handleErrorWithFlat
并将它们打包成文件EitherTUtils.scala
// Place this in a new file and then use it like so:
//
// import EitherTUtils.EitherTFutureAdditions
//
// val et: EitherT[Future, String, Int] =
// EitherT(Future.failed[Either[String, Int]](new Exception("example")))
// et recoverLeft {
// case e: Exception => s"Failed with reason ${e.getMessage}"
// }
//
object EitherTUtils {
/**
* Convenience additions for recovering and handling Future.failed within an EitherT
*
* @see [[cats.ApplicativeError]] for recover, recoverWith, handleError, handleErrorWith, and attemptT
*
* @param et a Futured EitherT
* @tparam A the Either's left type
* @tparam B the Either's right type
*/
implicit class EitherTFutureAdditions[A, B](et: EitherT[Future, A, B]) {
val me = EitherT.catsDataMonadErrorFForEitherT[Future, Throwable, A]
/**
* Recover from certain errors from this EitherT's Future (if failed) by mapping them to the EitherT's
* left value.
*
* @see [[recoverWithFlat]] for mapping to an Either[Future, A, B]
*
* @see [[handleErrorWithFlat]] to handle any/all errors.
*/
def recoverLeft(pf: PartialFunction[Throwable, A]): EitherT[Future, A, B] =
me.recoverWith[B](et) {
case t: Throwable =>
EitherT.fromEither[Future](Left(pf(t)))
}
/**
* Recover from certain errors from this EitherT's Future (if failed) by mapping them to the EitherT's
* value.
*
* @see [[recoverLeft]] for mapping to an EitherT's left value.
*
* @see [[handleErrorWithFlat]] to handle any/all errors.
*/
def recoverWithFlat(pf: PartialFunction[Throwable, Either[A, B]]): EitherT[Future, A, B] =
me.recoverWith[B](et) {
case t: Throwable =>
EitherT.fromEither[Future](pf(t))
}
/**
* Handle any error from this EitherT's Future (if failed) by mapping them to the EitherT's left value.
*
* @see [[recoverWithFlat]] for handling only certain errors
*
* @see [[handleErrorLeft]] for mapping to the EitherT's left value
*/
def handleErrorLeft(pf: PartialFunction[Throwable, A]): EitherT[Future, A, B] =
me.handleErrorWith[B](et) { t =>
EitherT.fromEither[Future](Left[A, B](pf(t)))
}
/**
* Handle any error from this EitherT's Future (if failed) by mapping them to the EitherT's value.
*
* @see [[recoverWithFlat]] for handling only certain errors
*
* @see [[handleErrorLeft]] for mapping to the EitherT's left value
*/
def handleErrorWithFlat(pf: PartialFunction[Throwable, Either[A, B]]): EitherT[Future, A, B] =
me.handleErrorWith[B](et) { t =>
EitherT.fromEither[Future](pf(t))
}
}
}
我认为这些可能是我对猫的第一笔贡献,但是在浏览图书馆布局几小时后,我意识到所做的修改并不容易,而且我尚不具备以< 不需要其他项目贡献者的大量工作。
一旦我更好地了解了cats库的结构,我可能会再试一次。
答案 2 :(得分:0)
这是您的EitherTUtils
的通用版本:
import cats.data.EitherT
object EitherTUtils {
implicit class EitherTRecoverErrors[F[_], A, B, E](et: EitherT[F, A, B])(implicit me: MonadError[F, E]) {
type FE[X] = EitherT[F, A, X]
implicit val ME: MonadError[FE, E] = implicitly
def recoverLeft(pf: PartialFunction[E, A]): EitherT[F, A, B] =
ME.recoverWith(et)(pf.andThen(EitherT.leftT(_)))
def recoverWithFlat(pf: PartialFunction[E, Either[A, B]]): EitherT[F, A, B] =
ME.recoverWith(et)(pf.andThen(EitherT.fromEither(_)))
def handleErrorLeft(f: E => A): EitherT[F, A, B] =
ME.handleErrorWith(et)(f.andThen(EitherT.leftT(_)))
def handleErrorWithFlat(f: E => Either[A, B]): EitherT[F, A, B] =
ME.handleErrorWith(et)(f.andThen(EitherT.fromEither(_)))
}
}
object Usage {
import EitherTUtils._
import cats.implicits._
import scala.concurrent.ExecutionContext.Implicits.global
val e: EitherT[Future, String, Int] = EitherT.liftF(Future.failed(new RuntimeException)).recoverLeft {
case e: IllegalStateException =>
e.getMessage
}
}
我同意猫可以使与“失败的” EitherT一起使用变得更加容易,希望我们在将来的版本中会看到类似的东西。