liveBook · Manning

Product

As explained in Functional Programming in Scala, Second Edition

A product is a construction that combines two algebraic or effectful structures componentwise into a structure over pairs.

Product combines two values that live in the same structure. For parsers, it means: run one parser, then another; if both succeed, keep both results as a pair. A parser for A and a parser for B therefore produce a parser for (A, B). The symbolic spelling ** is an alias for product. section 9.2.1

Build a nonempty repetition

A one-or-more parser need not be primitive. First parse one p, then parse p.many, and combine the head and tail with ::. Product supplies the paired inputs; map2 transforms that pair into the desired result. This separates sequencing from the rule for combining successful values. section 9.2.1 section 9.8

This distinction is useful because product says only “keep both,” while map2 says “run both and calculate a new result.” Defining map2 through product and map makes the relationship explicit: product creates Parser[(A, B)], then map applies the combining function. The same pattern builds listOfN and separated sequences. section 9.2.1 section 9.8

Recursive parser combinators expose an operational requirement: the second parser must be accepted nonstrictly. A direct many definition recursively constructs p.many before parsing begins and can overflow the stack. Deferring that recursive parser lets product and map2 sequence each step only when it is needed. section 9.2.1 section 9.8

extension [A](p: Parser[A])
  def product[B](p2: Parser[B]): Parser[(A, B)]
  def **[B](p2: Parser[B]): Parser[(A, B)] = product(p2)    #1

The parser signature makes the result shape visible: sequencing Parser[A] with Parser[B] preserves both values in a tuple. section 9.2.1

For applicative structures, product is the general operation that combines two effects into an effect containing a pair, usually defined with map2. Its associativity law permits either grouping of three products, provided a tuple reassociation map aligns the nested pair shapes. Without that law, derived operations such as map3 would need separate left- and right-grouped variants. section 12.5.2 section 12.9

Product obeys two especially useful expectations:

  • Associativity: (a ** b) ** c and a ** (b ** c) have equivalent behavior after reshaping nested pairs. section 9.8 section 12.5.2
  • Naturality: mapping each component before product agrees with taking product first and mapping the pair afterward. section 9.8 section 12.9

How Functional Programming in Scala, Second Edition covers it

How deep it goes
Defines parser and applicative product, derives map2, and states associativity and naturality laws; implementation internals are not developed here.
Examples
Uses one-or-more character parsing, repeated parsing, list construction, nested tuples, and JSON key-value parsing.
What it assumes
Introduces product through concrete parsers before generalizing it to Applicative effects.
What you can do after
Build it from scratch by defining map2 from product and using it for repetition and fixed-length parser combinators.
How it connects
Connects product to map2, map, many, Applicative, monads, functors, 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.