Random

type Generator a
A Generator is like a recipe for generating certain random values. So a Generator Int describes how to generate integers and a Generator String describes how to generate strings.

To actually run a generator and produce the random values, you need to use functions like generate and initialSeed.

Primitive Generators

bool : Generator Bool
Create a generator that produces boolean values. The following example simulates a coin flip that may land heads or tails.

type Flip = Heads | Tails

coinFlip : Generator Flip
coinFlip = map (\b -> if b then Heads else Tails) bool
int : Int -> Int -> Generator Int
Generate 32-bit integers in a given range.

float : Float -> Float -> Generator Float
Generate floats in a given range. The following example is a generator that produces decimals between 0 and 1.

probability : Generator Float
probability = float 0 1

Data Structure Generators

pair : Generator a -> Generator b -> Generator (a, b)
Create a pair of random values. A common use of this might be to generate a point in a certain 2D space. Imagine we have a collage that is 400 pixels wide and 200 pixels tall.

randomPoint : Generator (Int,Int)
list : Int -> Generator a -> Generator (List a)
Create a list of random values.

floatList : Generator (List Float)
floatList = list 9 (float 0 1)

intList : Generator (List Int)
intList = list 5 (int 0 100)

intPairs : Generator (List (Int, Int))
intPairs = list 10 <| pair (int 0 100) (int 0 100)

Custom Generators

map : (a -> b) -> Generator a -> Generator b
Transform the values produced by a generator. The following examples show how to generate booleans and letters based on a basic integer generator.

bool : Generator Bool
bool = map ((==) 1) (int 0 1)

lowercaseLetter : Generator Char
lowercaseLetter = map (\n -> Char.fromCode (n + 97)) (int 0 25)

uppercaseLetter : Generator Char
uppercaseLetter = map (\n -> Char.fromCode (n + 65)) (int 0 25)

map2 : (a -> b -> c) -> Generator a -> Generator b -> Generator c
Combine two generators. This function is used to define things like pair where you want to put two generators together.

pair : Generator a -> Generator b -> Generator (a,b)
pair genA genB = map2 (,) genA genB

map3 : (a -> b -> c -> d) -> Generator a -> Generator b -> Generator c -> Generator d
Combine three generators. This could be used to produce random colors.

import Color

rgb : Generator Color.Color
rgb = map3 Color.rgb (int 0 255) (int 0 255) (int 0 255)

hsl : Generator Color.Color
hsl = map3 Color.hsl (map degrees (int 0 360)) (float 0 1) (float 0 1)

map4 : (a -> b -> c -> d -> e) -> Generator a -> Generator b -> Generator c -> Generator d -> Generator e
Combine four generators.

map5 : (a -> b -> c -> d -> e -> f) -> Generator a -> Generator b -> Generator c -> Generator d -> Generator e -> Generator f
Combine five generators.

andThen : (a -> Generator b) -> Generator a -> Generator b
Chain random operations, threading through the seed. In the following example, we will generate a random letter by putting together uppercase and lowercase letters.

letter : Generator Char
letter = bool |> andThen upperOrLower

upperOrLower : Bool -> Generator Char
upperOrLower b = if b then uppercaseLetter else lowercaseLetter

-- bool : Generator Bool
-- uppercaseLetter : Generator Char
-- lowercaseLetter : Generator Char

Generate Values

generate : (a -> msg) -> Generator a -> Cmd msg
Create a command that will generate random values.

Read more about how to use this in your programs in The Elm Architecture tutorial which has a section specifically about random values.

step : Generator a -> Seed -> (a, Seed)
Generate a random value as specified by a given Generator.

In the following example, we are trying to generate a number between 0 and 100 with the int 0 100 generator. Each time we call step we need to provide a seed. This will produce a random number and a new seed to use if we want to run other generators later.

So here it is done right, where we get a new seed from each step call and thread that through.

seed0 = initialSeed 31415

-- step (int 0 100) seed0 ==> (42, seed1)
-- step (int 0 100) seed1 ==> (31, seed2)
-- step (int 0 100) seed2 ==> (99, seed3)

Notice that we use different seeds on each line. This is important! If you use the same seed, you get the same results.

-- step (int 0 100) seed0 ==> (42, seed1)
-- step (int 0 100) seed0 ==> (42, seed1)
-- step (int 0 100) seed0 ==> (42, seed1)

type Seed
A Seed is the source of randomness in this whole system. Whenever you want to use a generator, you need to pair it with a seed.

initialSeed : Int -> Seed
Create a “seed” of randomness which makes it possible to generate random values. If you use the same seed many times, it will result in the same thing every time! A good way to get an unexpected seed is to use the current time.