This library helps you request pseudo-random values.
It is an implementation of Permuted Congruential Generators by M. E. O'Neil. It is not cryptographically secure.
A Spec is a specifcation for requesting random values. For example,
here is a specification for requesting numbers between 1 and 10 inclusive:
import Tepa.Random as Random
oneToTen : Random.Spec Int
oneToTen =
Random.int 1 10Notice that we are not actually requesting any numbers yet!
We are just constructing the request body that describes what kind of values we want.
To actually get random values, you create a promise with the request function:
import Tepa exposing (Promise)
import Tepa.Random as Random
newNumber : Promise m Int
newNumber =
Random.request oneToTenEach time you run this promise, it checks the oneToTen specification and produces
random integers between one and ten.
When testing scenarios, you specify the target request for your response with the Spec:
import Tepa.Scenario as Scenario exposing (Scenario)
respondToRandomInt : Scenario flags m e
respondToRandomInt =
Scenario.randomResponse
mySession
(Scenario.textContent "Respond `1` to the first unresolved `oneToTen` request.")
{ layer = myLayer
, spec = oneToTen
, value = 1
}
-- If there is no unresolved `oneToTen` request at the time, the test fails.Request 32-bit integers in a given range.
import Tepa exposing (Promise)
import Tepa.Random as Random
singleDigit : Spec Int
singleDigit =
Random.int "singleDigit" 0 9
closeToZero : Spec Int
closeToZero =
Random.int "closeToZero" -5 5
anyInt : Spec Int
anyInt =
Random.int "anyInt" Random.minInt Random.maxIntThe string argument is the ID of the Spec, and is used to check the equivalence
of the two Specs in scenario testing. Be sure to specify unique IDs within the
same layer.
This promise can produce values outside of the range [minInt,
maxInt] but sufficient randomness is not guaranteed.
This is the TEPA version of int.
import Tepa.Random as Random
probability : Random.Spec Float
probability =
Random.float "probability" 0 1The probability specification specifies values between zero and one with
a uniform distribution. Say it requests a value p. We can then check if
p < 0.4 if we want something to happen 40% of the time.
The string argument is the ID of the Spec, and is used to check the equivalence
of the two Specs in scenario testing. Be sure to specify unique IDs within the
same layer.
This is the TEPA version of float.
Request values with equal probability. Say we want a random suit for some cards:
import Tepa.Random as Spec
type Suit
= Diamond
| Club
| Heart
| Spade
suit : Random.Spec Suit
suit =
Random.uniform "suit" Diamond [ Club, Heart, Spade ]That requests all Suit values with equal probability, 25% each.
The string argument is the ID of the Spec, and is used to check the equivalence
of the two Specs in scenario testing. Be sure to specify unique IDs within the
same layer.
Note: Why not have uniform : String -> List a -> Spec a as the API? It looks
a little prettier in code, but it leads to an awkward question. What do you do
with uniform identifier []? How can it request an Int or Float? The current API
guarantees that we always have at least one value, so we never run into that
question!
Request values with a weighted probability. Say we want to simulate a loaded die that lands on ⚄ and ⚅ more often than the other faces:
import Tepa.Random as Random
type Face
= One
| Two
| Three
| Four
| Five
| Six
roll : Random.Sepc Face
roll =
Random.weighted "roll"
( 10, One )
[ ( 10, Two )
, ( 10, Three )
, ( 10, Four )
, ( 20, Five )
, ( 40, Six )
]So there is a 40% chance of getting Six, a 20% chance of getting Five, and
then a 10% chance for each of the remaining faces.
The string argument is the ID of the Spec, and is used to check the equivalence
of the two Specs in scenario testing. Be sure to specify unique IDs within the
same layer.
Note: I made the weights add up to 100, but that is not necessary. I always
add up your weights into a total, and from there, the probability of each case
is weight / total. Negative weights do not really make sense, so I just flip
them to be positive.
Alias for Random.maxInt.
The underlying algorithm works well in a specific range of integers. It can request values outside of that range, but they are “not as random”.
The maxInt that works well is 2147483647.
Alias for Random.minInt.
The underlying algorithm works well in a specific range of integers. It can request values outside of that range, but they are “not as random”.
The minInt that works well is -2147483648.
Send a request for random values. Say you want to request random points:
Each time you run the
newPointpromise, it will resolve to a new 2D point like(57, 18)or(-82, 6).