【问题标题】:Cats EitherT.collectRight can't find Alternative[Future]Cats EitherT.collectRight 找不到替代方案[Future]
【发布时间】:2019-09-24 03:07:55
【问题描述】:

我正在尝试为 Cats EitherT.collectRight 查找示例。我有一个EitherT[Future, String, Event],当我做collectRight,时,我得到了

Error:(79, 18) could not find implicit value for parameter FA: cats.Alternative[scala.concurrent.Future]
            elem.collectRight

我在范围内有一个隐含的ExecutionContext,所以this 常见问题解答不适用。

【问题讨论】:

    标签: scala functional-programming scala-cats


    【解决方案1】:

    Alternative[Future] 没有实例,也不应该有。这是类型定义:

    trait Alternative[F[_]] extends Applicative[F] with MonoidK[F]
    

    Applicative[Future] 很好。但是MonoidK[F]Future 没有意义。来自MonoidK的评论:

    • Monoid[A] 允许组合 A 值,也意味着存在 是一个“空”A 值,用作身份。

    • MonoidK[F] 允许组合两个 F[A] 值,用于任何 A。它 也意味着对于任何A,都有一个“空”F[A] 值。这 组合操作和空值只取决于 F 的结构,但不在A 的结构上。

    您将如何为任何A 构造一个“空”Future[A]?您如何将两个Future[A]s 合二为一?你可以看到List 是如何实现的,但对我来说,Future 是荒谬的。也许你有一些你期望的行为,你可以自己实现Applicative[Future]。但我怀疑真正的问题是你想要的不是collectRight

    例如,您希望这会发生什么?

    val e: EitherT[Future, String, Event] = Future(Left("hello"))
    val result: Future[Event] = e.collectRight // should return what?... failure?
    

    【讨论】:

    • 我预计您的示例未来会失败,例如Future.failed(new NoSuchElementException("whatever"))。我所追求的是将EitherT 转换成另一种形状,但这似乎非常困难。我可以使用fold 之一来做到这一点,但希望有一个更简单的选择。
    【解决方案2】:

    这是对 Abhijit Sarkar 对 JoeK 的回答的评论的回答,评论太大了。

    首先我同意乔的观点,你试图使用collectRight 是非常可疑的。看起来您真正需要的是getOrElsegetOrElseF。例如,这似乎与您评论中描述的行为相匹配

    import scala.concurrent.duration._
    import scala.concurrent.ExecutionContext.Implicits.global
    
    case class Event(val a: Int)
    
    val eGood: EitherT[Future, String, Event] = EitherT[Future, String, Event](Future(Right(Event(42))))
    val resultGood: Future[Event] = eGood.getOrElseF(Future.failed(new NoSuchElementException("whatever")))
    val eBad: EitherT[Future, String, Event] = EitherT[Future, String, Event](Future(Left("hello")))
    val resultBad: Future[Event] = eBad.getOrElseF(Future.failed(new NoSuchElementException("whatever")))
    
    println("good = " + scala.concurrent.Await.result(resultGood, 1 second))
    println()
    scala.concurrent.Await.result(resultBad, 1 second)) // don't need println as there will be exception anyway
    

    打印

    好 = 事件 (42)

    线程“主”java.util.NoSuchElementException 中的异常:随便
    在 sg.cats.CatsMain$.$anonfun$resultBad$1(CatsMain.scala:32))
    在 ...

    请注意,Future.failed(new NoSuchElementException("whatever")) 实际上是 Alternative[Future] 应该具有的 empty 实现。这是没有适合所有场景的解决方案的地方之一。不过,如果您太无聊而无法一直输入,并且遇到与所有案例匹配的相同失败,您可以创建隐式操作,例如:

    final class MyEitherFutureOps[A, B](val eab: EitherT[Future, A, B]) extends AnyVal {
    
      import cats.instances.future._
    
      def rightOrFailure(implicit ec: ExecutionContext): Future[B] = eab.getOrElseF(Future.failed(new NoSuchElementException("whatever")))
    }
    
    object MyEitherFutureOps {
      implicit def ops[A, B](eab: EitherT[Future, A, B]): MyEitherFutureOps[A, B] = new MyEitherFutureOps[A, B](eab)
    
    }
    

    然后你可以把它当作

    import MyEitherFutureOps._
    
    val eGood: EitherT[Future, String, Event] = EitherT[Future, String, Event](Future(Right(Event(42))))
    val resultGood: Future[Event] = eGood.rightOrFailure
    val eBad: EitherT[Future, String, Event] = EitherT[Future, String, Event](Future(Left("hello")))
    val resultBad: Future[Event] = eBad.rightOrFailure
    

    效果与上例相同。

    【讨论】:

    • resultGoodresultBad 一样,都失败了?
    • @AbhijitSarkar,没有resultGood 是包含Event(42)Future。这是你想要的行为,不是吗?我更新了代码示例以阐明输出。
    【解决方案3】:

    post 已经快 2 年了,但简单点怎么样:

    val e: EitherT[Future, String, Event] = ???
    val result: Future[Event] = e.value.flatMap {
      case Right(event) => Future.successful(event)
      case Left(e)      => Future.failed(new NoSuchElementException("whatever with: " + e))
      //case Left(e) => Future.successful(???) //some recover from String to Event
    }
    

    还是我错过了什么?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-26
      • 2011-11-14
      • 2017-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多