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





