Haskell puts all side effects in the IO monad, which passes around the RealWorld. This is unsatisfactory for a number of reasons, and Haskellers have spilled much ink on effects systems. As I recently noted, there are distinctions in how one handles effects at the logical level: in particular, randomness is different from array writes.

In Haskell, the IO type is defined as:

newtype IO a = IO (RealWorld -> (a, RealWorld))

One can imagine a monad for randomness which carries around the seed for a generator:

newtype Rand a = Rand (Seed -> (a, Seed))

These rhyme but there is a moral difference between RealWorld and Seed: the RealWorld cannot be duplicated (or discarded), while pseudorandom number generators split:

split : Seed -> (Seed, Seed)

In the language of Girard, this is object vs. object factory: a RealWorld is an object, and a Seed begets a Seed factory.

Intriguingly, Verse (a functional language) makes this distinction. Established functional programming languages lack facilities to handle linearity; there is a need to adopt modern ideas from logic in order to clarify various problems in the field.