mapN над составленным Применить
Я знаю что могу сочинять 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
?
1 ответ
Это именно то, что 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
,