【问题标题】:How to stack applicative functors in Scala如何在 Scala 中堆叠应用函子
【发布时间】:2016-04-20 18:06:01
【问题描述】:

当您的计算步骤是独立的时,应用函子经常被提及作为 monad 的替代品。它们经常提到的一个优点是,当你想堆叠应用程序时不需要转换器,因为F[G[X]] 始终也是一个应用程序。 假设我有以下功能:

def getDataOption(): Option[Data]
def getUserFuture(): Future[User]
def process(data: Data, user: User)

我想要优雅的堆叠以获得Future[Option[User]]Future[Option[Data]] 并与process 映射。

到目前为止,我只是想出了这个(使用 Cats):

Applicative[Future]
  .compose[Option]
    .map2(
      Applicative[Future].pure(getDataOption()),
      getUserFuture().map(Applicative[Option].pure))(process)

但我确信这远非理想。有没有更优雅和通用的方法来实现同样的目标?

【问题讨论】:

    标签: scala scalaz scala-cats


    【解决方案1】:

    这里最困难的是类型推断。这是我能做的最好的了

      // for the Applicative[Future[Option[?]]
      import cats.Applicative
    
      implicit val fo = {
        import cats.std.future._
        import cats.std.option._
        Applicative[Future].compose[Option]
      }
    
      // for the |@| syntax
      import cats.syntax.cartesian._
    
      // to guide type inference
      type FutureOption[A] = Future[Option[A]]
    
      ((Future(getDataOption): FutureOption[Data]) |@|
        getUserFuture.map(Option.apply)).map(process _)
    

    【讨论】:

    • 谢谢,如果可能的话,我想类似于 Eff/Emm monad 的东西可以方便地剥离样板。
    • 我认为这里最简单的做法可能是抓住OptionT,但您可能可以使用(send(getDataOption) |@| send(getUserFuture)).map(process _).runOption.detach.run 获得最终的Future[Option[A]] 与Eff(以及与Emm 类似的东西) )。
    • 对。但是,我想继续使用应用程序。我的问题的重点是看到一个值得称赞的应用属性的实际应用,它们可以在不使用变压器的情况下堆叠。
    • 看起来你刚刚为 Eff 添加了一个非常好的应用程序支持。谢谢,埃里克! atnos-org.github.io/eff-cats/…
    • 老实说,我仍然很惊讶它完全有效!因此,如果您发现任何问题,请报告。
    猜你喜欢
    • 2019-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多