Talking with a friend earlier today we decided to make an experiment in declaring generic mutable variables that can be used in `IO`

, `ST`

or `State`

monads. I don’t think this is useful, but it was fun to write. Here is result.

```
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FunctionalDependencies #-}
import Data.Array.MArray
import Data.Array.IO
import Control.Monad.ST
import Data.STRef
import qualified Data.List.NonEmpty as NE
import Data.List.NonEmpty (NonEmpty)
import qualified Control.Monad.State.Strict as State
import Data.Foldable (forM_)
import Control.Monad (when)
import Test.QuickCheck
import Test.QuickCheck.Monadic
```

Let’s define the abstract interface. `v`

will be the type of variables that can operate on the monad `m`

, holding values of type `a`

. We need three operation: create a variable, read, and write to it.

Notice we had to use `FunctionalDependencies`

to ease type inference. I don’t like this, there is probably a better way.

A utility function to do both read and write passing through a function:

Now we can provide different implementations for variables. First one in `IO`

We represent the value as an array of a single element. This is obviously overkill, but the goal was also to experiment with the low level array API

```
instance Var IOVar IO a where
new = fmap IOVar . newArray ((), ())
get (IOVar ar) = readArray ar ()
set (IOVar ar) a = writeArray ar () a
```

The implementation is straightforward, reading and writing from/to the the array. Creation needs to take care of wrapping the array in the `IOVar`

constructor. Notice that `()`

is a valid index type for arrays, and it makes obvious in the type the fact that the array has a single element.

Providing an implementation in the `ST`

monad is not much harder. Here, we could also use an `STArray`

, but we go directly to `STRef`

for simplicity

```
newtype STVar s a = STVar (STRef s a)
instance Var (STVar s) (ST s) a where
new = fmap STVar . newSTRef
get (STVar ref) = readSTRef ref
set (STVar ref) a = writeSTRef ref a
```

The code looks very similar to the `IO`

case.

Finally, let’s try to implement a variable in the `State`

monad. For a variable holding values of type `a`

, it is enough to maintain state `a`

. So we can define

And now to create an instance of `Var`

we can do

```
instance Var StateVar (State.State a) a where
new x = State.StateT $ \_ -> return (StateVar x, x)
get _ = State.get
set _ = State.put
```

`get`

and `set`

are simple. `new`

requires some care. Initializing the variable means setting the state to a given value, so it can then be read by `get`

. So in `new`

we need it ignore the current state, and set it to `x`

. The types are not enough to ensure correctness, there is a wrong implementation that also compiles:

And that’s it, we have the three types of variables we wanted. Now we can write a stateful looking algorithm, computing the maximum of a list is a good example. The way people do this in non functional languages usually is:

- initialize a variable
`max`

with the first element of the list - go through all other elements:
- if the current element is larger than
`max`

, update`max`

with the new value

- if the current element is larger than
- when done iterating the list return
`max`

We can express exactly this algorithm with our variables, even more, we can do it in a way that is generic for every type of `Var`

and every supported `Monad`

Take a look at the signature: given a non empty list (`NonEmpty a`

), we return its maximum in some monad (`Monad m`

). We can do this as long as `a`

can be ordered (`Ord a`

), and there is some type of variable `v`

which works for the monad `m`

and the type `a`

(`Var v m a`

). The type signature expresses all this pretty well.

```
myMaximum xs = do
max <- new (NE.head xs) -- initialize a new var
forM_ (NE.tail xs) $ \a -> do -- for each el after the head
maxSoFar <- get max -- get the current maximum
when (a > maxSoFar) $ -- compare with current element
set max a -- update if needed
get max
```

Just like in the description of the algorithm, we create a variable and update it for every element that is larger than the initial value. When done iterating we return the last value hold by the variable.

Now we need to write some tests:

In `IO`

```
testIO :: (NonEmptyList Int) -> Property
testIO (NonEmpty xs) = monadicIO $ do
mine <- run . myMaximum . NE.fromList $ xs
assert $ mine == maximum xs
```

In `ST`

```
testST :: (NonEmptyList Int) -> Property
testST (NonEmpty xs) = monadicST $ do
mine <- run . myMaximum . NE.fromList $ xs
assert $ mine == maximum xs
```

And in `State`

```
testState :: (NonEmptyList Int) -> Bool
testState (NonEmpty xs) =
State.execState (mine xs) whoCares == maximum xs
where
mine = myMaximum . NE.fromList
whoCares = 42
```

Running the QuickCheck tests

```
main = do
quickCheckWith opts testIO
quickCheckWith opts testST
quickCheckWith opts testState
where opts = stdArgs {maxSuccess = 5000}
```

Success!