Haskell is a great imperative language, and writing programs that can re-assign state is a really fun advanced topic! This is definitely not the approach you want right now, but come back to it some day 🙂

It takes a bit of effort to define an environment that models global mutable variables. Once you get the hang of it, though, the precision of the types ends up being pretty handy.

We're going to be using the lens and mtl libraries.

{-# LANGUAGE TemplateHaskell #-} import Control.Lens import Control.Monad.State

I'll stick with using integers as your question does, but we'll throw in a type alias to remind ourselves that they are being used as the type of the elephant variable.

type Elephant = Integer

You wanted a program whose global mutable state has an elephant. So first let's define what it means to have an elephant. Lens captures this notion nicely.

class HasElephant a where elephant :: Lens' a Elephant

Now we can define function , which assigns a new value to elephant .

function :: (MonadState s m, HasElephant s) => Elephant -> m () function x = elephant .= x

The constraints MonadState s m and HasElephant s are saying our program must be able to hold mutable state of some type s , and the type s must have an elephant.

Let's also define a program that prints the elephant.

printElephant :: (MonadState s m, HasElephant s, MonadIO m) => m () printElephant = use elephant >>= (liftIO . print)

This program does I/O (printing), so we have an additional constraint MonadIO m that says our program type m must be able to do I/O.

The elephant variable is probably only one part of some larger program state. Let's define a data type here to represent the entire state (which we'll name Congo just to be cute because the Congo Basin is one place where elephants live).

data Congo = Congo { _congoElephant :: Elephant } makeLenses ''Congo

(See Control.Lens.TH for a little bit about makeLenses does here using Template Haskell.)

We must define the way in which the Congo has an elephant.

instance HasElephant Congo where elephant = congoElephant

Now we can write an example program. Our program will print the value of elephant , then change the value of elephant , then print it again.

main' :: StateT Congo IO () main' = do printElephant function 2 printElephant

Then we can run this program.

main :: IO () main = Congo 0 & runStateT main' & void

The output is: