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
