liveBook · Manning

mapAccum

As explained in Functional Programming in Scala, Second Edition

mapAccum is a traversal operation that threads an accumulator through a structure while transforming its elements and preserving its shape.

mapAccum traverses a structure while carrying state from one element to the next. Each step returns a new accumulator and a replacement element, producing a transformed structure with the original shape. section 12.9 section 12.9

The operation combines two familiar capabilities:

  • Like map, it replaces every element with a transformed value. section 12.9
  • Like foldLeft, it threads an accumulator through the traversal. section 12.9
  • Unlike foldLeft, it retains an output element at every position instead of keeping only the final state. section 12.9
  • The traversal preserves the input shape, so operations over trees or other structured data retain their structural constraints. section 12.7.3

Building reverse and zip

To reverse a traversable structure, convert its elements to a reversed list and use that list as the accumulator: each step emits the remaining head and passes the tail forward. The same pattern implements foldLeft by returning () for every output and retaining only the final accumulator. A generic zip can instead carry the remaining elements of the second structure, failing when they run out or emitting Option values to support mismatched lengths. section 12.9 section 12.7.3

Listing 12.13 A more flexible implementation of zip
extension [A](fa: F[A])
  def zipL[B](fb: F[B]): F[(A, Option[B])] =
    fa.mapAccum(fb.toList):
      case (a, Nil) => ((a, None), Nil)
      case (a, b :: bs) => ((a, Some(b): Option[B]), bs)
    .apply(0)
 
  def zipR[B](fb: F[B]): F[(Option[A], B)] =
    fb.mapAccum(fa.toList):
      case (b, Nil) => ((None, b), Nil)
      case (b, a :: as) => ((Some(a): Option[A], b), as)
    .apply(0)

Compare zipL and zipR: each traverses one structure while consuming the other as a list, choosing which structure supplies the result shape and how missing elements become None. section 12.7.3

How Functional Programming in Scala, Second Edition covers it

How deep it goes
Explains state threading through outputs, demonstrates reverse, foldLeft, and zip implementations, and connects the operation to traversal.
Examples
Uses reverse, foldLeft, and zipping structures, including padding mismatched shapes with Option.
What it assumes
Uses map, foldLeft, and traversable structures as comparison points while distinguishing Foldable from Functor.
What you can do after
Build it from scratch to implement reverse, foldLeft, and shape-aware zip operations over traversable structures.
How it connects
Connects traversal with Functor, Foldable, foldLeft, State, and Applicative.

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.