liveBook · Manning

Applicative functor

As explained in Functional Programming in Scala, Second Edition

An applicative functor is an abstraction that applies effectful functions to effectful arguments while combining their contexts.

An applicative functor combines values that carry the same kind of context—such as optionality, parsing, validation, or parallelism—when the shape of the computation is known in advance. It is weaker than a monad: it can sequence independent effects, but cannot choose a later effect from an earlier result. section 12.0 section 12.3.1 section 12.3.2

The core operations are `unit`, which lifts an ordinary value into `F`, and `map2`, which combines `F[A]` and `F[B]` with a pure `(A, B) => C`. From these, `map`, `product`, `sequence`, `traverse`, and higher-arity combinators follow. An alternative formulation uses `apply` to apply an effectful function `F[A => B]` to an effectful argument `F[A]`. section 12.2 section 12.9

Listing 12.1 Creating the Applicative interface
trait Applicative[F[_]] extends Functor[F]:
  // primitive combinators
  def unit[A](a: => A): F[A]
  extension [A](fa: F[A])
    def map2[B, C](fb: F[B])(f: (A, B) => C): F[C]
 
  // derived combinators
  extension [A](fa: F[A])
    def map[B](f: A => B): F[B] =                #1
      fa.map2(unit(()))((a, _) => f(a))          #2
 
  def traverse[A, B](
    as: List[A])(f: A => F[B]): F[List[B]] =     #3
    as.foldRight(unit(List[B]()))((a, acc) => f(a).map2(acc)(_ :: _))

The interface makes the division explicit: `unit` and `map2` are primitive, while mapping and traversal are derived without `flatMap`. section 12.2

Combining independent lookups

Two `Option` lookups for Alice's department and salary can be combined with `map2`: if both values exist, format a message; otherwise the result is absent. Neither lookup depends on the other, so the computation has a fixed structure. section 12.3.1

Dependency is the boundary. Looking up Bob's employee ID before choosing department and salary lookups requires `flatMap`, because the ID determines the next computations. Likewise, a parser for fixed date-and-temperature columns is applicative; parsing a header to select a row parser dynamically is monadic. section 12.3.1 section 12.3.2

Applicative structure has practical consequences:

  • Use the weaker interface for `traverse` when only `unit` and `map2` are needed, allowing more effect types to participate. section 12.1 section 12.4
  • Expose a parser's grammar structure before execution when it avoids `flatMap`, giving an interpreter more information for possible optimizations. section 12.4
  • Compose applicative functors by products or nesting, unlike monads in general. section 12.5.3
  • Accumulate validation errors with `Validated`, which is applicative but has no monad instance. section 12.9

Applicative laws make combinations predictable. Left and right identity say that combining with `unit(())` preserves a value. Associativity says grouping products does not change meaning, and naturality says mapping before combining agrees with combining before mapping transformed results. section 12.5.1 section 12.5.3 section 12.9

Applicative functors connect directly to traversal. A `Traverse` can turn a structure of effects into an effect containing the structure, and `State` as the applicative effect supports generic operations such as indexing elements or collecting them into a list. section 12.8 section 12.7.2

How Functional Programming in Scala, Second Edition covers it

How deep it goes
Defines `unit`, `map2`, and `apply`; contrasts monadic dependency and states identity, associativity, and naturality laws.
Examples
Uses Option map lookups, fixed and header-driven CSV parsers, validation, and State-based indexing traversals.
What it assumes
Builds on Monad operations and functional effects while introducing Applicative as a distinct, weaker interface.
What you can do after
Build it from scratch by implementing `unit` and `map2` or `apply`, then deriving traversal and higher-arity combinators.
How it connects
Connects Monad, Functor, Traverse, State, Monoid, Semigroup, Validated, Option, and Parser.

Also explained in

Compare how 2 books explain applicative functor →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Programming in Scala, Second Edition. The section links point to the parts of the book it draws on.