We will now prove that there is no state monad in Haskell. By a state monad, we mean a monad satisfying Gibbons and Hinze’s four laws:

put s >> put s' = put s' put s >> get = put s >> return s get >>= put = return () get >>= λs → get >>= k s = get >>= λs → k s s

The reader may object that there is a monad satisfying these four laws:

type State s a = ⊥ return = ⊥ (>>=) = ⊥ get = ⊥ put = ⊥

This monad lacks a certain something, though. We will disqualify it by assuming that return () ≠ ⊥ .

One obstacle for our proof is that we may not eta-expand or eta-reduce anything without justification. For example, the state monad laws say that get >>= put = return () , but how do we know that get >>= λx → put x is also equal to return () ? Yikes! Thankfully, we can freely eta-expand or eta-reduce the argument to >>= :

m >>= f = {- return is a unit for >>= -} (m >>= f) >>= return = {- associativity of >>= -} m >>= (λx → f x >>= return) = {- return is a unit for >>= -} m >>= λx → f x

With that proved, we can apply the monad laws in the carefree way we are used to. We start by observing that the fourth law gives us get >> get >>= k = get >> k (just expand the definition of >> ). Now we can show that get >> return () = return () , for:

get >> return () = {- get >>= put = return () -} get >> get >>= put = {- get >> get >>= k = get >>= k -} get >>= put = {- get >>= put = return () -} return ()

From the above equation, we get for any x that get >> return () >> x = return () >> x or, simplifying, get >> x = x . Finally, letting x be ⊥, we get get >> ⊥ = ⊥ , or, expanding the definition of >> :

get >>= λx → ⊥ = ⊥.

This equation is the problem. Notice that the following similar-looking expression oughtn’t be ⊥:

get >>= λx → if x == "Hello" then ⊥ else return () ≠ ⊥

After all, if we run it in the state "Hello" , it returns () , while ⊥ diverges. In general, we have:

get >>= f = ⊥, if f x = ⊥ for all x get >>= f ≠ ⊥, if f x = return () for some x

The first statement is just our problem equation restated; we will prove the second one in the next section. From these two properties we will derive the promised lot of nonsense. The idea is that applying seq to get >>= f tells us whether f is defined anywhere — something we cannot compute in Haskell.

We define a predicate over type a to mean a function of type a → () . The idea is that a predicate returns () if its argument satisfies the predicate, and otherwise diverges. An existential quantifier for the type a is a higher-order predicate — a function of type (a → ()) → () — which holds of a predicate p if there exists a value satisfying p . In other words, if exists is an existential quantifier, then exists p = () if there exists an x for which p x = () , otherwise exists p = ⊥ .

Notice that in pure Haskell we cannot define an existential quantifier for the vast majority of types. For example, we might try to define one on booleans as exists p = p False || p True , but the || here must be “parallel or” , which we cannot write in Haskell. We can only define an existential quantifier for a domain that has a top element, in which case exists p = p ⊤ .

But, if we have a genuine state monad, we can define an existential quantifier for any type!

exists :: (a → ()) → () exists p = (get >>= f) `seq` () where f x = case p x of () → return ()

We should check that this is indeed an existential quantifier.

If p is ⊥ everywhere, then f = λx → ⊥ . The first of our two laws above then tells us that get >>= f = ⊥ and therefore exists p is ⊥.

On the other hand, if p x is () for a certain x , then f x = return () , and from above we know that get >>= f ≠ ⊥ , so exists p = () .