liveBook · Manning

Functor

As explained in Functional Programming in Scala, Second Edition

A functor is an abstraction that provides a map operation for transforming values inside a computational structure while preserving that structure.

A functor captures a recurring use of map: transform values inside a context without changing that context’s structure. List, Option, Gen, Parser, and Par can each support this pattern even though their concrete map signatures differ. In Scala, the abstraction is parameterized by a type constructor F[_], rather than by one chosen container. section 11.1 section 11.7

trait Functor[F[_]]:
  extension [A](fa: F[A])
    def map[B](f: A => B): F[B]

The interface says that, for any element type A and result type B, a function A => B turns F[A] into F[B]. An instance supplies the evidence that its chosen F supports this operation. section 11.1

The point is not merely to give map a shared name. Once code depends only on Functor[F], it can be derived by following types and reused for every lawful instance. For example, a value F[(A, B)] can be distributed into a pair (F[A], F[B]) by mapping each projection; an Either containing F[A] or F[B] can be lifted to F[Either[A, B]] by mapping the corresponding constructor. section 11.1

Distributing a list of pairs

For List[(A, B)], distribute is unzip: map once to collect first components and once to collect second components. The resulting lists retain the input length, order, and corresponding positions—not because of a List-specific implementation, but because map must preserve structure. section 11.1 section 11.1.1

Lawfulness gives map its meaning. Identity requires x.map(a => a) == x, so mapping the identity cannot throw an exception, remove a list element, or turn Some into None. Composition requires x.map(f).map(g) == x.map(f andThen g), allowing successive element transformations to be treated as one transformation. section 11.1.1 section 11.7

The laws support reasoning at the interface level:

  • Identity preserves the entire value when the element function does nothing. section 11.1.1
  • Composition preserves the result of combining two mapped transformations into one. section 11.1.1
  • Structural preservation lets generic operations retain facts such as a list’s length and ordering. section 11.1.1

Functor is a base abstraction, not a guarantee of richer composition. Every monad is a functor, and every applicative functor is a functor, but the converses do not hold. Traverse extends Functor because traversal can define map using the identity type; Foldable cannot generally extend Functor, since visiting elements does not provide enough information to rebuild the original shape with a new element type. section 11.7 section 12.9 section 12.9

How Functional Programming in Scala, Second Edition covers it

How deep it goes
Defines the Scala interface, derives distribute and codistribute, and justifies identity and composition laws through structural preservation.
Examples
Uses List, Option, Gen, Parser, Par, generic unzip, and codistribute to demonstrate map’s shared shape.
What it assumes
Assumes Scala type constructors and familiar map operations while introducing Functor as a parametric interface.
What you can do after
Apply it to derive structure-preserving transformations and generic combinators from map alone.
How it connects
Connects map to type constructors, monoids, monads, applicative functors, Traverse, and Foldable.

Also explained in

Compare how 6 books explain 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.