在哪里使用`ApplicativeError`而不是`Either`?

问题描述 投票:2回答:1

ApplicativeError[F,E] + F[A],有Either[E, A]。两者都传达了该函数可能会因E而失败或因A而成功的消息,但我不确定它们向客户端传达的有关处理错误的预期方式的不同消息:

def f1[F[_]: Applicative[F]]: F[Either[E, A]]
def f2[F[_]: ApplicativeError[F,E]]: F[A]

我理解f1的意思是:客户负责错误处理。但是f2对客户端意味着如何处理错误?

scala scala-cats applicative cats-effect
1个回答
3
投票

ApplicativeError[F, E]假定E的类型以某种方式编码在F中,并且您只能创建ApplicativeError[F, E]的实例,因为对于此特定的F,有意义的是错误E。范例:

  • ApplicativeError[Task, Throwable]-Task使用Throwable作为错误通道,因此将Throwable公开为错误代数是有意义的。由于Cats Effect的Sync[F]实现了MonadError[F, Throwable],而Cs又实现了ApplicativeError[F, Throwable]-Cats Effect的许多类型类都假设您只处理Throwable
  • ApplicativeError[Task[Either[E, *]], E]-在这种组合中,您会在E类型的特定定义以及F参数中都具有E-这对于所有类型的功能键都是典型的:Task[Either[E, *]]EitherT[Task, E, *] ,ZIO的IO[E, A],依此类推

接口ApplicativeError[F, E]不能自行处理错误。但是它公开了方法:

  • raiseError[A](e: E): F[A]-会产生错误
  • [handleErrorWith[A](fa: F[A])(f: (E) ⇒ F[A]): F[A]-处理它的人]

以便您可以告诉它如何处理。

[两者都工作时都没有假设错误和F的性质,只是Applicative可能会失败。如果仅使用F并键入类,则可以使用这些方法从错误中恢复。并且,如果您知道呼叫站点上F的确切类型(因为它被硬编码为TaskIOCoeval等),则可以直接使用恢复方法。

主要区别是结果F[Either[E, A]]不会告诉调用方E应该被视为失败。 F[A]告知可能只有A成功值。另外,一个需要Applicative,而另一个需要ApplicativeError,因此创建值所需的“功率”有所不同-如果您看到ApplicativeError,即使结果中没有E,您也可以认为该方法可能会失败因为它需要更强大的类型类。

但是,当然,它不是一成不变的,主要是表达意图,因为到处都有F[A],您可以使用F[Either[E, A]]ApplicativeError[F, E]进行相互转换(甚至还有类似attempt[A](fa: F[A]): F[Either[E, A]]的方法或fromEither[A](x: Either[E, A]): F[A])。因此,在您的应用程序的一部分上,您可以使用F[A]E代数,但是只有一个纯函数可以使用Either[E, A] => B-您可以进行转换,映射,必要时进行转换返回。

TL; DR,主要是表达意图,因为两者在道德上是平等的。

© www.soinside.com 2019 - 2024. All rights reserved.