State Monad - SML
Table of Contents
1. Introduction
We can think of the State monad as a Reader monad which is also a Writer monad, but that's probably not the best way to derive the State monad.
Wadler introduced the idea of encoding state into a monad back in 1992
(if not earlier) in his paper "The Essence of Functional
Programming". But the formalism of State
in terms of StateT
monad transformers seems to be from Jones's 1995 paper "Functional
Programming with Overloading and Higher-Order Polymorphism".
Confusingly, early papers mix up the State
monad with the ST
monad.
We can view this as a generalization of the IO Monad, where we now have:
type RealWorld = ... type IO a = State RealWorld a
2. Heuristic Derivation
We basically have a state be described along the lines of:
datatype ('s,'a) State = State of ('s -> 'a*'s);
This is tempting, but wrong. Why?
We do not want to export the constructor, because we do not want the user to do pattern matching. We could ostensibly just do:
type ('s, 'a) State = 's -> 'a * 's;
But this won't do. Why not? Because almost any function could qualify for
being a term of type State
. That's bad.
What we do is:
abstype ('s, 'a) State = State of ('s -> 'a * 's) where fun state (f : 's -> 'a * 's) = State f; fun runState t st = (* magic... *); fun return x = state (fn st => (x, st)); (* "k" for "kontinuation" *) fun bind act k = state (fn st => let val (x, st') = runState act st in runState (k x) st' end); end;
Probably a more honest answer is to have State of {runState : 's -> 'a*'s}
.
2.1. Stack Computation
One fascinating derivation is to consider a simple "stack computer",
modeled by a list of integers. We also have a register (a "top of stack"
value). The "state" 's
in this case is int list
, the 'a
in this
case is the "top of stack" register int
.
Here return (x : int) = State (fn s => (x, s))
updates the "top of stack"
register.
The bind function composes state-transition functions:
(* f : top-of-stack -> State *) fun bind (State st) f = State (fn s => let val (x, s') = st s val (State st') = f x in st' s' end);
We would then have the basic operations like push, pop, top, etc., be implemented using monadic constructor:
datatype ('a * 's) State = State of ('s -> 'a * 's); (* push : int -> State (int list) int *) fun push n = State (fn s => (n, n::s)); (* pop : State (int list) int *) val pop = State (fn (x::xs) => (x, xs)); (* top : State (int list) int *) val top = State (fn (x::xs) => (x, x::xs));
I really like this example, since it emphasizes with clarity the essential aspect of the state monad as abstracting the notion of a stateful computation. I found this example from:
- Wayne Snyder,
Lecture 12: State Monads.
Boston University, course CS 320.
3. Implementation Details
3.1. Higher-Order Types
Haskell can have higher-order types (where types and type constructors are given as constructors). If we try to naively translate this into Standard ML, there is nothing "obviously" comparable.
What we should do instead is to use SML Functors. After all, we have a Monad be encoded using an ML structure, so if our intuitive understanding of a Monad transformer is (according to Haskell):
class (forall m. Monad m => Monad (t m)) => MonadTrans t where lift :: (Monad m) => m a -> t m a
It has to satisfy the following two laws:
lift . return = return
lift (m >>= f) = lift m >>= (lift . f)
What we should do is define a monad transformer as a functor.
functor
4. OCaml Implementation
Cambridge L28 taught in 2014–2015 has, in its lecture notes, an implementation in OCaml which is very straightforward:
module type MONAD = sig type 'a t val return : 'a -> 'a t val (>>=) : 'a t -> ('a -> 'b t) -> 'b t end module type STATE = sig include MONAD type state val get : state t val put : state -> unit t val runState : 'a t -> init:state -> state * 'a end
5. References
- Mark P Jones,
"Functional Programming with Overloading and Higher-Order Polymorphism".
Eprint, 1995, 40 pages. - NLab, State Monad
- Ravi Chugh and Stuart Kurtz,
"State Monad I".
Lecture U. Chicago, CMSC-16100, 2016. - School of Haskell on State monad.
- William Yao,
Deriving the State monad from first principles.
Blog post dated July 12, 2020.
5.1. OCaml Implementations
- Ćukasz Stafiniak,
"Functional Programming, lecture 8: Monads".
Slides - Xavier Leroy,
"Functional programming languages, Part IV: monadic transformations, monadic programming".
slides - Daniel Perez, Implementation