7

I am scala and functional newbie and trying to learn applicatives.

val o1 = Some(1)
val o2 = Some(2)
val o3 = Some(3)
val result = (o1 |@| o2 |@| o3) {_ + _ + _}

There is a very good read about Applicatives and Functors here

As per this blog,

Operator |@| is the product operation

and

combining your applicatives into a product by using |@| results in an ApplicativeBuilder which takes a function to perform on the product (since product + map is a very common use case)

I am finding it very difficult to understand above two statements from the blog. Any example with code in scala to understand this will be helpful.

Community
  • 1
  • 1
mogli
  • 1,549
  • 4
  • 29
  • 57

1 Answers1

6

I think the key take away from the post, which should help reason about applicative functors is this sentence:

Hey, so you got your function wrapped into a bit of a context, huh? Not to worry, I know how to apply those kind of wrapped functions

Applicative provides a way of applying a function wrapped in a context over other wrapped values.

|@| and the underlying type ApplicativeBuilder are just scalazs way of constructing these applicatives via a DSL.

From the documentation (emphasis mine):

Whereas a scalaz.Functor allows application of a pure function to a value in a context, an Applicative also allows application of a function in a context to a value in a context (ap)


Operator |@| is the product operation

By "product operation" the OP means that it is the operation which takes two values and wraps them inside the ApplicativeBuilder.

|@| is a method that when invoked, returns an instance of ApplicativeBuilder:

final def |@|[B](fb: F[B]) = new ApplicativeBuilder[F, A, B] {
  val a: F[A] = self
  val b: F[B] = fb
}

Where F is a first order kind which has an Apply instance defined:

implicit val F: Apply[F]

Where Apply is just an Applicative without the point method.

combining your applicatives into a product by using |@| results in an ApplicativeBuilder which takes a function to perform on the product (since product + map is a very common use case)

If you we take your example and simplify it a bit for two Option[Int]s:

import scalaz.Scalaz._

val o1 = 1.some
val o2 = 1.some
val result: ApplicativeBuilder[Option, Int, Int] = o1 |@| o2
val finalRes: Option[Int] = result.apply(_ + _)

We:

  1. Apply |@| to two instances an of Option[Int] and get back an ApplicativeBuilder[Option, Int, Int]. Option here is our F, which has an instance of Apply.
  2. After getting back an instance of the builder, we invoke it's apply method. We provide it with a function of shape Int -> Int and it gives us back a Option[Int], meaning we are still inside the context, but with the operation applied to our values.
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321