Apply is Functor that also has apply method. Scalaz defines Apply[F[_]] trait with ap abstract method.
Having a higher kind A and hight kind of A to B mapping we can get higher kind B. And since Apply is also a functor we also have
We can do interesting things with those two. We can define ap2 for example, which will take, F[A], F[B], F[(A, B) ⇒ C] and return F[C]
And we can extends this to apN to go as many levels deep as we want. We can also define apply2 which will take F[A], F[B] and (A, B) ⇒ C mapping and retrun F[C]. Note that unlike ap2, it takes (A, B) ⇒ C instead of F[(A, B) ⇒ C].
This one also we can extends to applyN. Since apply2 takes (A, B) ⇒ C mapping we can just not map it to another type and return (A, B) tuple.
And of course we can define tupleN using applyN. Having apply2 we can define lift2 which will take (A, B) ⇒ C mapping and lift it to (F[A], F[B]) ⇒ F[C] mapping.
We can also define liftN based on applyN.
Of course we don’t have to derive all those factions ourself since scalaz is so awesome it provides those for us. It also defines following syntax functions:
- <*> for ap.
- tuple for tuple2.
- *> which uses apply2 with (_, b) ⇒ b mapping to discard the left.
- <* which uses apply2 with (a, _) ⇒ a mapping to discard the right.
- ⊛ and |@| applicative builders as alternatives to applyN.
- ^, ^^, ^^^, ^^^^, ^^^^^ and ^^^^^^ for apply2, apply3, apply4, apply5, apply6, apply7
Since both Option and Lists are Apply I’m gonna demonstrate those methods on them with short examples:
Output
1.some <*> ((_:Int) + 1).some Some(2)
none <*> ((_:Int) + 1).some None
1.some <*> none None
1.some.tuple(2.some) Some((1,2))
none.tuple(2.some) None
1.some.tuple(none) None
List(1,2).tuple(List("a", "b")) List((1,a), (1,b), (2,a), (2,b))
1.some *> 2.some Some(2)
none *> 2.some None
1.some *> none None
1.some <* 2.some Some(1)
none <* 2.some None
1.some <* none None
("a".some ⊛ "b".some)(_ + _) Some(ab)
^("a".some, "b".some)(_ + _) Some(ab)
^^("a".some, "b".some, "c".some)(_ + _ + _) Some(abc)