liveBook · Manning

Parfoldmap

As explained in Functional Programming in Scala, Second Edition

A parallel fold-map operation that maps and reduces sequence elements as parallel computations.

parFoldMap maps every element of an IndexedSeq and reduces the mapped results as parallel computations. It combines parallelism with a Monoid, whose associative operation permits results to be grouped by halves without changing the final answer. section 10.9 section 10.3

The implementation separates the two stages:

  • Use parMap to transform the input sequence, producing a Par[IndexedSeq[B]]. section 10.9
  • Reduce the mapped sequence with foldMapV, using a Monoid lifted to Par[B]. section 10.9
  • Define par so combine applies the original monoid operation through Par.map2 and empty lifts the original identity with Par.unit. section 10.9

Implementation shape

def par[A](m: Monoid[A]): Monoid[Par[A]] = new: def combine(a1: Par[A], a2: Par[A]) = a1.map2(a2)(m.combine) val empty = Par.unit(m.empty) def parFoldMap[A, B](as: IndexedSeq[A], m: Monoid[B])(f: A => B): Par[B] = Par.parMap(as)(f).flatMap(bs => foldMapV(bs, par(m))(b => Par.lazyUnit(b)) ) section 10.9

The design works because the reduction is associative: a sequence may be combined left-to-right, by halves, or through another grouping while preserving the result. The same foldMapV structure can therefore support sequential and parallel reductions, with different efficiency characteristics. section 10.3 section 10.9

import fpinscala.parallelism.Nonblocking.*
 
def par[A](m: Monoid[A]): Monoid[Par[A]]
def parFoldMap[A, B](as: IndexedSeq[A], m: Monoid[B])(f: A => B): Par[B]

Use the compact signatures to compare the Monoid lifting step with the final parallel fold-map operation. section 10.3

How Functional Programming in Scala, Second Edition covers it

How deep it goes
Works through the implementation of par and parFoldMap, but defers the underlying parallel library internals.
Examples
Uses balanced sequence splitting and a Monoid lifted to parallel computations.
What it assumes
Assumes Monoid, foldMapV, and Par operations, while demonstrating how to lift a monoid into Par.
What you can do after
Build it from scratch by defining par and composing parMap with foldMapV.
How it connects
Connects Monoid, foldMapV, parMap, Par, and associativity.

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.