通过使用 Scala 和 Cats(或者可能是另一个专注于类别理论和/或函数式编程的库)以最具功能性(代数)的方式解决这个问题的最佳方法是什么?
资源
如果我们有以下方法来执行 REST API 调用来检索单条信息?
type FutureApiCallResult[A] = Future[Either[String, Option[A]]]
def getNameApiCall(id: Int): FutureApiCallResult[String]
def getAgeApiCall(id: Int): FutureApiCallResult[Int]
def getEmailApiCall(id: Int): FutureApiCallResult[String]
如您所见,它们产生异步结果。在 API 调用期间,Either monad 用于返回可能的错误,而 Option 用于在 API 未找到资源时返回 None(这种情况不是错误,而是可能的和所需的结果类型)。以功能方式实现的方法
case class Person(name: String, age: Int, email: String)
def getPerson(id: Int): Future[Option[Person]] = ???
如果任何 API 调用失败或任何 API 调用返回 None(无法组合整个 Person 实体),则此方法应使用上面定义的三个 API 调用方法异步组合并返回 Person 或 None要求
出于性能原因,所有 API 调用都必须以并行方式完成
我猜
我认为最好的选择是使用 Cats Semigroupal 已验证 但是当我试图处理 Future 和这么多嵌套的 Monad 时我迷路了 :S
谁能告诉我您将如何实现这一点(即使更改方法签名或主要概念)或将我指向正确的资源?我对 Cats 和 Algebra 在编码方面很陌生,但我想学习如何处理这种情况,以便我可以在工作中使用它。
最佳答案
这里的关键要求是它必须并行完成。这意味着使用 monad 的明显解决方案已经过时,因为 monadic bind 是阻塞的(它需要结果,以防它必须在其上进行分支)。所以最好的选择是使用 applicative。
我不是 Scala 程序员,所以我无法向您展示代码,但这个想法是应用仿函数可以提升多个参数的函数(常规仿函数使用 map
提升单个参数的函数)。在这里,您将使用类似 map3
的内容。解除 Person
的三参数构造函数工作在三个 FutureResult
s。搜索“Scala 中的应用程序 future ”会返回一些点击。 Either
也有应用实例和 Option
而且,与 monad 不同,应用程序可以很容易地组合在一起。希望这可以帮助。
关于scala - 以功能方式进行多个 API 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48138007/