This is an alternative site for discovering Elm packages. You may be looking for the official Elm package site instead.

# Random

This library helps you generate pseudo-random values.

This library is all about building generators for whatever type of values you need. There are a bunch of primitive generators like bool and int that you can build up into fancier generators with functions like list and map.

Note: This is an implementation of the Portable Combined Generator of L'Ecuyer for 32-bit computers. It is almost a direct translation from the System.Random module. It has a period of roughly 2.30584e18.

# Generators

type Generator a = Generator (Seed -> (a, Seed))

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.

int 0 10   -- an integer between zero and ten
int -5 5   -- an integer between -5 and 5

int minInt maxInt  -- an integer in the widest range feasible

This function can produce values outside of the range [minInt, maxInt] but sufficient randomness is not guaranteed.

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)
randomPoint =
pair (int -200 200) (int -100 100)
list : Int -> Generator a -> Generator (List a)

Create a list of random values.

floatList : Generator (List Float)
floatList =
list 10 (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 : Generator a -> (a -> Generator b) -> 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` \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.

# Generate Values Manually

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 = Seed { state : State , next : State -> (Int, State) , split : State -> (State, State) , range : State -> (Int,Int) }

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.

# Constants

maxInt : Int

The maximum value for randomly generated 32-bit ints: 2147483647

minInt : Int

The minimum value for randomly generated 32-bit ints: -2147483648

effect module Random where { command = MyCmd } exposing
( Generator, Seed
, bool, int, float
, list, pair
, map, map2, map3, map4, map5
, andThen
, minInt, maxInt
, generate
, step, initialSeed
)

{-| This library helps you generate pseudo-random values.

This library is all about building [`generators`](#Generator) for whatever
type of values you need. There are a bunch of primitive generators like
[`bool`](#bool) and [`int`](#int) that you can build up into fancier
generators with functions like [`list`](#list) and [`map`](#map).

similarly.

[json]: https://evancz.gitbooks.io/an-introduction-to-elm/content/interop/json.html

> *Note:* This is an implementation of the Portable Combined Generator of
L'Ecuyer for 32-bit computers. It is almost a direct translation from the
module. It has a period of roughly 2.30584e18.

# Generators
@docs Generator

# Primitive Generators
@docs bool, int, float

# Data Structure Generators
@docs pair, list

# Custom Generators
@docs map, map2, map3, map4, map5, andThen

# Generate Values
@docs generate

# Generate Values Manually
@docs step, Seed, initialSeed

# Constants
@docs maxInt, minInt

-}

import Basics exposing (..)
import List exposing ((::))
import Platform
import Platform.Cmd exposing (Cmd)
import Time

-- PRIMITIVE GENERATORS

{-| 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
-}
bool : Generator Bool
bool =
map ((==) 1) (int 0 1)

{-| Generate 32-bit integers in a given range.

int 0 10   -- an integer between zero and ten
int -5 5   -- an integer between -5 and 5

int minInt maxInt  -- an integer in the widest range feasible

This function *can* produce values outside of the range [[`minInt`](#minInt),
[`maxInt`](#maxInt)] but sufficient randomness is not guaranteed.
-}
int : Int -> Int -> Generator Int
int a b =
Generator <| \(Seed seed) ->
let
(lo,hi) =
if a < b then (a,b) else (b,a)

k = hi - lo + 1
-- 2^31 - 87
base = 2147483561
n = iLogBase base k

f n acc state =
case n of
0 -> (acc, state)
_ ->
let
(x, state') = seed.next state
in
f (n - 1) (x + acc * base) state'

(v, state') =
f n 1 seed.state
in
( lo + v % k
, Seed { seed | state = state' }
)

iLogBase : Int -> Int -> Int
iLogBase b i =
if i < b then
1
else
1 + iLogBase b (i // b)

{-| The maximum value for randomly generated 32-bit ints: 2147483647 -}
maxInt : Int
maxInt =
2147483647

{-| The minimum value for randomly generated 32-bit ints: -2147483648 -}
minInt : Int
minInt =
-2147483648

{-| 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
-}
float : Float -> Float -> Generator Float
float a b =
Generator <| \seed ->
let
(lo, hi) =
if a < b then (a,b) else (b,a)

(number, newSeed) =
step (int minInt maxInt) seed

negativeOneToOne =
toFloat number / toFloat (maxInt - minInt)

scaled =
(lo+hi)/2 + ((hi-lo) * negativeOneToOne)
in
(scaled, newSeed)

-- DATA STRUCTURES

{-| 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)
randomPoint =
pair (int -200 200) (int -100 100)

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

{-| Create a list of random values.

floatList : Generator (List Float)
floatList =
list 10 (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)
-}
list : Int -> Generator a -> Generator (List a)
list n (Generator generate) =
Generator <| \seed ->
listHelp [] n generate seed

listHelp : List a -> Int -> (Seed -> (a,Seed)) -> Seed -> (List a, Seed)
listHelp list n generate seed =
if n < 1 then
(List.reverse list, seed)

else
let
(value, newSeed) =
generate seed
in
listHelp (value :: list) (n-1) generate newSeed

-- CUSTOM GENERATORS

{-| 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)

-}
map : (a -> b) -> Generator a -> Generator b
map func (Generator genA) =
Generator <| \seed0 ->
let
(a, seed1) = genA seed0
in
(func a, seed1)

{-| Combine two generators.

This function is used to define things like [`pair`](#pair) where you want to
put two generators together.

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

-}
map2 : (a -> b -> c) -> Generator a -> Generator b -> Generator c
map2 func (Generator genA) (Generator genB) =
Generator <| \seed0 ->
let
(a, seed1) = genA seed0
(b, seed2) = genB seed1
in
(func a b, seed2)

{-| 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)
-}
map3 : (a -> b -> c -> d) -> Generator a -> Generator b -> Generator c -> Generator d
map3 func (Generator genA) (Generator genB) (Generator genC) =
Generator <| \seed0 ->
let
(a, seed1) = genA seed0
(b, seed2) = genB seed1
(c, seed3) = genC seed2
in
(func a b c, seed3)

{-| Combine four generators.
-}
map4 : (a -> b -> c -> d -> e) -> Generator a -> Generator b -> Generator c -> Generator d -> Generator e
map4 func (Generator genA) (Generator genB) (Generator genC) (Generator genD) =
Generator <| \seed0 ->
let
(a, seed1) = genA seed0
(b, seed2) = genB seed1
(c, seed3) = genC seed2
(d, seed4) = genD seed3
in
(func a b c d, seed4)

{-| Combine five generators.
-}
map5 : (a -> b -> c -> d -> e -> f) -> Generator a -> Generator b -> Generator c -> Generator d -> Generator e -> Generator f
map5 func (Generator genA) (Generator genB) (Generator genC) (Generator genD) (Generator genE) =
Generator <| \seed0 ->
let
(a, seed1) = genA seed0
(b, seed2) = genB seed1
(c, seed3) = genC seed2
(d, seed4) = genD seed3
(e, seed5) = genE seed4
in
(func a b c d e, seed5)

{-| 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` \b ->
if b then uppercaseLetter else lowercaseLetter

-- bool : Generator Bool
-- uppercaseLetter : Generator Char
-- lowercaseLetter : Generator Char
-}
andThen : Generator a -> (a -> Generator b) -> Generator b
andThen (Generator generate) callback =
Generator <| \seed ->
let
(result, newSeed) =
generate seed

(Generator genB) =
callback result
in
genB newSeed

-- IMPLEMENTATION

{-| 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`](#generate) and [`initialSeed`](#initialSeed).
-}
type Generator a =
Generator (Seed -> (a, Seed))

type State = State Int Int

{-| 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.
-}
type Seed =
Seed
{ state : State
, next  : State -> (Int, State)
, split : State -> (State, State)
, range : State -> (Int,Int)
}

{-| 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

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)
-}
step : Generator a -> Seed -> (a, Seed)
step (Generator generator) seed =
generator seed

{-| Create a &ldquo;seed&rdquo; 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.
-}
initialSeed : Int -> Seed
initialSeed n =
Seed
{ state = initState n
, next = next
, split = split
, range = range
}

{-| Produce the initial generator state. Distinct arguments should be likely
to produce distinct generator states.
-}
initState : Int -> State
initState s' =
let
s = max s' -s'
q  = s // (magicNum6-1)
s1 = s %  (magicNum6-1)
s2 = q %  (magicNum7-1)
in
State (s1+1) (s2+1)

magicNum0 = 40014
magicNum1 = 53668
magicNum2 = 12211
magicNum3 = 52774
magicNum4 = 40692
magicNum5 = 3791
magicNum6 = 2147483563
magicNum7 = 2137383399
magicNum8 = 2147483562

next : State -> (Int, State)
next (State s1 s2) =
-- Div always rounds down and so random numbers are biased
-- ideally we would use division that rounds towards zero so
-- that in the negative case it rounds up and in the positive case
-- it rounds down. Thus half the time it rounds up and half the time it
-- rounds down
let
k = s1 // magicNum1
s1' = magicNum0 * (s1 - k * magicNum1) - k * magicNum2
s1'' = if s1' < 0 then s1' + magicNum6 else s1'
k' = s2 // magicNum3
s2' = magicNum4 * (s2 - k' * magicNum3) - k' * magicNum5
s2'' = if s2' < 0 then s2' + magicNum7 else s2'
z = s1'' - s2''
z' = if z < 1 then z + magicNum8 else z
in
(z', State s1'' s2'')

split : State -> (State, State)
split (State s1 s2 as std) =
let
new_s1 =
if s1 == magicNum6-1 then 1 else s1 + 1

new_s2 =
if s2 == 1 then magicNum7-1 else s2 - 1

(State t1 t2) =
snd (next std)
in
(State new_s1 t2, State t1 new_s2)

range : State -> (Int,Int)
range _ =
(0, magicNum8)

-- MANAGER

{-| Create a command that will generate random values.

tutorial][arch] which has a section specifically [about random values][rand].

[arch]: https://evancz.gitbooks.io/an-introduction-to-elm/content/architecture/index.html
[rand]: https://evancz.gitbooks.io/an-introduction-to-elm/content/architecture/effects/random.html
-}
generate : (a -> msg) -> Generator a -> Cmd msg
generate tagger generator =
command (Generate (map tagger generator))

type MyCmd msg = Generate (Generator msg)

cmdMap : (a -> b) -> MyCmd a -> MyCmd b
cmdMap func (Generate generator) =
Generate (map func generator)

init =

onEffects : Platform.Router msg Never -> List (MyCmd msg) -> Seed -> Task Never Seed
onEffects router commands seed =
case commands of
[] ->

Generate generator :: rest ->
let
(value, newSeed) =
step generator seed
in
Platform.sendToApp router value