Это именно то, для чего 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
для компиляции приведенного выше кода. В качестве альтернативы вы можете добавить некоторые параметры типа, но, в первую очередь, я не уверен, где именно они потребуются, и если вы в любом случае делать что-нибудь с кошками -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
.
person
Travis Brown
schedule
16.03.2019