A state token is a value whose type authorizes access to one local state thread. The token does not represent the state; it only marks which computations may access or mutate it. section 14.2.2
The token works with ST, a local-effects monad whose underlying state transition cannot be invoked directly. Keeping the token type private to a computation prevents mutable state from escaping its intended scope. section 14.2.1
The authorization pattern has three important properties:
- ST actions and the mutable references they create share the same S type. section 14.2.2
- The S value itself is never inspected; possessing a value of type S merely permits an ST action to run. section 14.2.2
- Opaque ST composition still supports map and flatMap while withholding direct access to the underlying function. section 14.2.1
Two cells, one authorization thread
An ST program allocates two mutable integer cells, reads them, swaps and increments their contents, then returns the pair. Choosing Nothing as S is syntactically possible, but the program cannot yet be run because ST remains opaque and no Nothing value can be supplied. section 14.2.2
Listing 14.2 Our new ST data type
opaque type ST[S, A] = S => (A, S)
object ST:
extension [S, A](self: ST[S, A])
def map[B](f: A => B): ST[S, B] =
s =>
val (a, s1) = self(s)
(f(a), s1)
def flatMap[B](f: A => ST[S, B]): ST[S, B] =
s =>
val (a, s1) = self(s)
f(a)(s1)
def apply[S, A](a: => A): ST[S, A] =
lazy val memo = a #1
s => (memo, s)
def lift[S, A](f: S => (A, S)): ST[S, A] = f
Inspect the ST definition to see how an abstract S parameter threads through pure-looking map and flatMap operations. section 14.2.1
