Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mapN over composed Apply

I know that I can compose Apply to work with nested structures, like in

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)
}

However, is there a way to convince the compiler to accept (o1, o2, o3).mapN(f) instead of Apply[List].compose[Option].map3(o1, o2, o3)(f), so that mapN gets applied using the composed Apply?

like image 998
Matthias Langer Avatar asked Jul 25 '26 07:07

Matthias Langer


1 Answers

This is exactly what cats.data.Nested is for:

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
}

(Note that you will need to enable the -Ypartial-unification compiler flag for the code above to compile. Alternatively you could add some type parameters, but off the top of my head I'm not sure exactly where they'd be required, and if you're doing anything with Cats -Ypartial-unification is pretty much necessary, anyway.)

You could also just make the composed instance available implicitly:

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)

This really isn't ideal, though—it's non-standard and extremely fragile (e.g. the type aliases are necessary to guide resolution).

In my view your best bet is just to write out Apply[List].compose[Option] explicitly and skip the fancy tuple syntax, but if you really have to have the fancy tuple syntax, go with Nested.

like image 86
Travis Brown Avatar answered Jul 28 '26 07:07

Travis Brown



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!