There is no difference between
Apply[Option].map(Some(1))(intToString)
and
Apply[Option].ap(Some(intToString))(Some(1))
Both are Some("1").
But there is a big difference between map and ap.
map comes from the type class Functor and has a signature
def map[A, B](fa: F[A])(f: A => B): F[B]
ap comes from the type class Apply and has a signature
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
So map applies a function A => B to a value in a context F[A] while ap applies a function F[A => B] in a context to a value in a context F[A].
For example
Apply[List].map(List(1, 2))(intToString)
is List("1", "2") while
Apply[List].ap(List(intToString, (i: Int) => intToString(i) + "a"))(List(1, 2))
is List("1", "2", "1a", "2a").
Apply[Option].map(fx)(f) can be None only when fx is None while Apply[Option].ap(ff)(fx) can be None when fx is None or ff is None.
apdirectly. Rather, I have used it implicitly using things liketupled,mapNandtraverse.apNlikemapN, but I guess the answer is the same.Applyis a specialized type class ofApplicative, which is also a Functor. Applicative providesapoperation. It’s very similar to Functor’s map but the function in the argument is already inF[_]domain. In a lot of cases like Monoids they can be used interchangeably with a few exceptions.apis more often used as a composition withmapof the shapeap(map), which is better known asliftA2. Please note thatapis a very fundamental operation and you should know when to use it instead offlatMap.