【问题标题】:Errors accumulation with MonoidMonoid 的错误累积
【发布时间】:2017-03-14 18:51:33
【问题描述】:

假设我有一个函数列表 E => Either[Exception, Unit] 在事件 E 上调用并累积错误以返回 Either[List[Exception], Unit]

type EventHandler = E => Either[Exception, Unit]

import cats.data.NonEmptyList

def fire(
  e: Event, 
  subscribers: List[EventHandler]
): Either[NonEmptyList[Exception], Unit] = ???

我想用cats 实现fire

 import cats.implicits._

 subscribers.foldMap (_ map (_.toValidatedNel))
            .map (.toEither)
            .apply(e)

这有意义吗?你会如何改进它?
如何将fire改为同时调用subscribers

【问题讨论】:

    标签: scala concurrency monoids scala-cats


    【解决方案1】:

    我可能会这样写:

    import cats.data.NonEmptyList, cats.implicits._
    
    type Event = String    
    type EventHandler = Event => Either[Exception, Unit]
    
    def fire(
      e: Event,
      subscribers: List[EventHandler]
    ): Either[NonEmptyList[Exception], Unit] =
      subscribers.traverse_(_(e).toValidatedNel).toEither
    

    (如果您未使用 2.12.1 或无法使用 -Ypartial-unification,则需要 traverseU_。)

    如果您希望调用同时发生,通常您会联系EitherT[Future, Exception, _],但这不会为您提供所需的错误累积。没有ValidatedT,但那是因为Applicative 直接组成。所以你可以这样做:

    import cats.Applicative
    import cats.data.{ NonEmptyList, ValidatedNel }, cats.implicits._
    import scala.concurrent.ExecutionContext.Implicits.global
    import scala.concurrent.Future
    
    type Event = String
    type EventHandler = Event => Future[Either[Exception, Unit]]
    
    def fire(
      e: Event,
      subscribers: List[EventHandler]
    ): Future[Either[NonEmptyList[Exception], Unit]] =
      Applicative[Future].compose[ValidatedNel[Exception, ?]].traverse(subscribers)(
        _(e).map(_.toValidatedNel)
      ).map(_.void.toEither)
    

    (请注意,如果您不使用 kind-projector,则需要写出类型 lambda 而不是使用 ?。)

    并向自己证明它同时发生:

    fire(
      "a",
      List(
        s => Future { println(s"First: $s"); ().asRight },
        s => Future { Thread.sleep(5000); println(s"Second: $s"); ().asRight },
        s => Future { println(s"Third: $s"); ().asRight }
      )
    )
    

    您会立即看到FirstThird

    【讨论】:

    • 谢谢!你为什么要写Applicative而不是Monoid。我猜Applicative 更通用,可能“更惯用”,但Monoid 对我来说似乎更简单。毕竟Validated 有一个Monoid 实例。这是有原因的。
    • @Michael 这是一个品味问题,但“对所有这些元素执行此操作”对我来说感觉更像是遍历。
    • 对于这种情况,幺半群不是“最不强大的抽象”,正如stackoverflow.com/a/19881777/521070 中所解释的那样?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-26
    • 2013-10-15
    • 2014-09-07
    • 1970-01-01
    相关资源
    最近更新 更多