首页 > 解决方案 > mapN 过组合 Apply

问题描述

我知道我可以组合Apply使用嵌套结构,例如

def mapAll[A, B, C, D](o1: List[Option[A]],
                       o2: List[Option[B]],
                       o3: List[Option[C]])
                      (f: (A, B, C) => D)
: List[Option[D]] = {
  import cats._
  import cats.implicits._
  Apply[List].compose[Option].map3(o1, o2, o3)(f)
}

但是,有没有办法说服编译器接受(o1, o2, o3).mapN(f)而不是Apply[List].compose[Option].map3(o1, o2, o3)(f),以便mapN使用组合应用Apply

标签: scalascala-cats

解决方案


这正是cats.data.Nested为了:

def mapAll[A, B, C, D](o1: List[Option[A]],
                       o2: List[Option[B]],
                       o3: List[Option[C]])
                      (f: (A, B, C) => D)
: List[Option[D]] = {
  import cats.data.Nested
  import cats.instances.list._, cats.instances.option._
  import cats.syntax.apply._

  (Nested(o1), Nested(o2), Nested(o3)).mapN(f).value
}

(请注意,您需要为-Ypartial-unification上面的代码启用编译器标志才能编译。或者,您可以添加一些类型参数,但我不知道在哪里需要它们,如果你无论如何,用 Cats 做任何事情-Ypartial-unification都是非常必要的。)

您也可以隐式地使组合实例可用:

import cats.Apply
import cats.instances.list._, cats.instances.option._
import cats.syntax.apply._

type ListOption[x] = List[Option[x]]

implicit val listOptionApply: Apply[ListOption] = Apply[List].compose[Option]

def mapAll[A, B, C, D](o1: ListOption[A],
                       o2: ListOption[B],
                       o3: ListOption[C])
                      (f: (A, B, C) => D)
: List[Option[D]] = (o1, o2, o3).mapN(f)

但是,这确实不理想——它是非标准的并且非常脆弱(例如,类型别名是指导解析所必需的)。

在我看来,你最好的选择就是Apply[List].compose[Option]明确地写出来并跳过花哨的元组语法,但如果你真的需要花哨的元组语法,那就用Nested.


推荐阅读