# The Random Monad in Elm

Monad is not a word in the Elm lexicon, and I guess there’s no reason to talk about it – other than for familiarity. Having learned some monads (and functors and applicatives) from Haskell, it was be helpful for me to identify familiar equivalents to get started.

To maintain purity, randomness in Elm is created by the Random monad, which is a `Generator`

type that tells the runtime to do the dirty work of generating randomness. The Elm app then gets back some (pseudo?)random value from the runtime, which can be used deterministically.

For example, a primitive generator:

```
int : Int -> Int -> Generator Int
```

… creates a generator for a random int in given range.

There is a single way to “extract” random values from generators:

```
generate : (a -> msg) -> Generator a -> Cmd msg
```

… which takes a constructor, a generator, and returns a `Cmd`

from the runtime.

The example from the Random module docs is illustrative.

```
point : Random.Generator (Int, Int)
point =
Random.pair (Random.int -100 100) (Random.int -100 100)
type Msg = NewPoint (Int, Int)
newPoint : Cmd Msg
newPoint =
Random.generate NewPoint point
```

## Applying Random

So let’s say we want to use randomness in something a bit more involved – like dividing a list into n sublists of random length.

One approach is with a fold, taking a list of random elements n times and accumulating them into a list of lists.

```
divideList : Int -> List Pair -> Random.Generator (List (List a))
divideList n pairs =
let
f i generatorAcc =
generatorAcc |> Random.andThen (takeRandom i)
in
List.range 1 n
|> List.foldr f (Random.constant ( [], pairs ))
|> Random.map Tuple.first
```

Here, the fold accumlator is a tuple of (collected sublists, list of remaining elements in original list). Since the accumulator will use Random generators, it needs to be initialized with `Random.constant`

, which is the equivalent of `pure`

– the minimal context for the Random monad.
`takeRandom`

has type signature:

```
takeRandom :
Int
-> ( List (List a), List a )
-> Random.Generator ( List (List a), List a )
```

… which means we need equivalent of Haskell’s `bind`

to use it with the monadic accumulator:

```
Control.Monad (=<<) :: Monad m => (a -> m b) -> m a -> m b
```

That’s the purpose of `Random.andThen`

:

```
andThen : (a -> Generator b) -> Generator a -> Generator b
```

Note also that `divideList`

uses `Random.map`

to extract the first value from the accumulator pair – equivalent to `fmap`

:

```
map : (a -> b) -> Generator a -> Generator b
```

The implementation of `takeRandom`

uses a generator from `Random.List.choices`

. It is otherwise straightforward: take all remaining elements if it’s the last sublist, otherwise accumulate a random number of randomly selected items.

```
takeRandom :
Int
-> ( List (List a), List a )
-> Random.Generator ( List (List a), List a )
takeRandom n ( acc, elems ) =
if n == 1 then
Random.constant ( elems :: acc, [] )
else
Random.int 1 (maxElems elems n)
|> Random.andThen
(\ct -> RL.choices ct elems)
|> Random.andThen
(\( xs, ys ) -> Random.constant ( xs :: acc, ys ))
```

(There’s probably a nicer way that doesn’t involve checking the index / sublist count.)