Some definitions first
import cats._, implicits._
val as = List(1, 2)
val bs = List("a", "b")
Curried funciton
If you have curried function, e.g.
val f = (i: Int) => (s: String) => Vector.fill(i)(s).mkString("")
Then pure f <*> as <*> bs
expression is directly translated to cats as
f.pure[List].ap(as).ap(bs)
And f <$> as <*> bs
becomes
as.map(f).ap(bs)
Yes, the order is not as natural anymore.
Uncurried function
In Scala very often you will deal with the functions taking multiple parameters:
val f2 = (i: Int, s: String) => Vector.fill(i)(s).mkString("")
// or val f2 = Function.uncurried(f)
For these, cats
provides CartesianBuilder
syntax:
(as |@| bs).map(f2)
Or, in the newer versions, tuple syntax with map#
method (that is subject to be renamed, IIRC)
(as, bs).map2(f2)
All these snippets evaluate to List("a", "b", "aa", "bb")