liveBook · Manning

Pure core

As explained in Functional Programming in Scala, Second Edition

The side-effect-free central portion of a program whose computations are expressed with pure functions.

A pure core is the side-effect-free center of a program: it computes values from inputs, while a thin outer layer obtains inputs and performs effects. This separation preserves the program’s behavior while making its central logic easier to understand, test, compose, and refactor. section 1.1.2 section 1.5

Refactor an effectful procedure by separating its responsibilities:

  • Identify the computation hidden inside the procedure with side effects. section 13.1
  • Make that computation a pure function that returns a result or a description of one. section 13.1
  • Leave input acquisition and output handling in procedures at the boundary. section 13.1
  • Keep the final effect, such as printing, around a pure expression rather than inside the computation. section 13.1

Computing a winner without printing

def winner(p1: Player, p2: Player): Option[Player] = if p1.score > p2.score then Some(p1) else if p1.score < p2.score then Some(p2) else None def winnerMsg(p: Option[Player]): String = p .map: case Player(name, _) => s"$name is the winner!" .getOrElse("It's a draw.") def contest(p1: Player, p2: Player): Unit = println(winnerMsg(winner(p1, p2))) Here, winner and winnerMsg form the pure core; contest interprets the result by printing it. The same core can support another outer layer, such as a user interface or file output. section 13.1

def winner(p1: Player, p2: Player): Option[Player] =   #1
  if p1.score > p2.score then Some(p1)
  else if p1.score < p2.score then Some(p2)
  else None
 
def contest(p1: Player, p2: Player): Unit =
  winner(p1, p2) match                                 #2
    case Some(Player(name, _)) => println(s"$name is the winner!")
    case None => println("It's a draw.")

Inspect the compact Scala refactoring from a printing contest procedure to a pure winner function and an effectful boundary. section 13.1

How Functional Programming in Scala, Second Edition covers it

How deep it goes
Explains decomposition into pure computation and effectful interpreters, then connects the pattern to IO and program descriptions.
Examples
Uses coffee purchasing, contest winners, console printing, charge aggregation, and effect descriptions as concrete examples.
What it assumes
Assumes functions and side effects, while introducing pure functions, referential transparency, and effect separation from first principles.
What you can do after
Apply it by extracting pure functions from effectful procedures and placing interpretation at the program boundary.
How it connects
Connects pure functions, referential transparency, IO, interpreters, and thin outer layers.

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.