liveBook · Manning

ST monad

As explained in Functional Programming in Scala, Second Edition

The ST monad is a functional programming abstraction that encapsulates local mutable state while preventing references created in one state thread from being used in another.

The ST monad permits local mutation inside an otherwise pure computation. Mutable state remains private to the computation, so its effects cannot be observed by unrelated code and the final result remains referentially transparent. section 14.0 section 14.2.3

The abstraction organizes mutable references around three guarantees:

  • Allocates, reads, and writes cells through ST actions rather than exposing a naked mutable reference. section 14.2.2
  • Tags each action and reference with a state-thread type S, which acts as authorization for accessing that state. section 14.2.2
  • Runs only computations whose result does not contain S, preventing local references from escaping their state thread. section 14.2.3

Purely functional in-place quicksort

A quicksort computation can allocate an STArray, mutate it through swap and partition operations, and freeze it into a result. ST.run exposes only the sorted value, not the temporary array or its mutations. section 14.2.5

def quicksort(xs: List[Int]): List[Int] =
  if xs.isEmpty then xs else ST.run([s] => () =>
    for
      arr    <- STArray.fromList[s, Int](xs)
      size   <- arr.size
      _      <- qs(arr, 0, size - 1)
      sorted <- arr.freeze
    yield sorted
  )

Shows the complete shape of a pure quicksort: create a mutable array locally, sort it through ST actions, then freeze the result. section 14.2.5

How Functional Programming in Scala, Second Edition covers it

How deep it goes
Descends from mutable-reference primitives through state-thread typing and safe execution, then applies the pattern to quicksort.
Examples
Uses STRef cells, swapping two integers, STArray operations, and in-place quicksort.
What it assumes
Assumes referential transparency and pure functions while developing a more mature account of locally hidden effects.
What you can do after
Build pure functions that use local mutation while preventing mutable references from escaping.
How it connects
Connects referential transparency, mutable state, polymorphism, type systems, arrays, and quicksort.

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.