1

Applicative provides "operator" <*>, which I can use as follows:

val f: (Int, Int) => Int = {(x, y) => x + y}
1.some <*> (2.some <*> f.curried.some)

In addition to that scalaz provides ApplicativeBuilder:

(1.some |@| 2.some)(f)

What are advantages of ApplicativeBuilder ? When would you use |@| instead of <*> ?

Michael
  • 41,026
  • 70
  • 193
  • 341

2 Answers2

3

Better type inference

scala> ^(1.right[String], 2.right[String])(_ + _)
<console>:16: error: type mismatch;
 found   : scalaz.\/[String,Int]
 required: ?F[?A]
Note that implicit conversions are not applicable because they are ambiguous:
 both method ToAssociativeOps in trait ToAssociativeOps of type [F[_, _], A, B](v: F[A,B])(implicit F0: scalaz.Associative[F])scalaz.syntax.AssociativeOps[F,A,B]
 and method ToBitraverseOps in trait ToBitraverseOps of type [F[_, _], A, B](v: F[A,B])(implicit F0: scalaz.Bitraverse[F])scalaz.syntax.BitraverseOps[F,A,B]
 are possible conversion functions from scalaz.\/[String,Int] to ?F[?A]
              ^(1.right[String], 2.right[String])(_ + _)
                                                 ^

scala> (1.right[String] |@| 2.right[String])(_ + _)
res1: scalaz.\/[String,Int] = \/-(3)
Kenji Yoshida
  • 3,108
  • 24
  • 39
0

There are not really advantages of one over the other, but as you can see the Applicative Builder does not require, that your function is curried and in the context of F. In my opinion it also has a more approachable usage of brackets.

You could also say that the Applicative Builder builds temporary objects, so that you should probably avoid it, when using in very performance critical code and/or loops. In this case you could use another alternative like: Applicative[Option].apply2(3.some, 4.some)(f). This is again very close to the |@| syntax, only that you do not have to count the number of parameters you want to provide for f(n1, n2, ...).

Markus
  • 1,293
  • 9
  • 10