Random Numbers

Eucalypt provides pseudo-random number generation through the io.random stream and a set of prelude functions.

The Random Stream

The io.random binding is an opaque PRNG stream, seeded from system entropy or the --seed command-line flag. Use random.* actions to draw values from it, or random.as-list to obtain a lazy cons-list of floats in [0, 1).

first-random: random.float(io.random).value

Because io.random is seeded from the system clock by default, it produces different values on each run. Use --seed for reproducible results:

eu --seed 42 example.eu

Random Number Generation

FunctionDescription
random-stream(seed)
stream-advance(n, s)
random-ret(v, stream)
random-bind(m, f, stream)
random.stream(seed)Create an opaque PRNG stream from integer seed
random.as-list(s)Convert an opaque random stream to a lazy cons-list of floats
random.float(s)State-monad action returning a random float in [0,1)
random.int(n, s)State-monad action returning a random integer in [0,n)
random.split(s)State-monad action that splits the stream into two independent streams. Returns a value/rest block where value and rest are each independent streams
random.choice(lst, stream)State-monad action returning a random element from list
random.shuffle(lst)State-monad action returning a shuffled copy of list
random.sample(n, lst, stream)State-monad action returning n elements sampled without replacement
random.run(action, stream)Run a random action on a stream; returns a value/rest block
random.eval(action, stream)Run a random action and return only the value
random.exec(action, stream)Run a random action and return only the remaining stream

Usage Pattern

The random namespace is a state monad. A random stream is provided at startup as io.random. Each operation takes a stream and returns a {value, rest} block:

result: random.int(6, io.random)
die-roll: result.value    # a number from 0 to 5

For multiple random values, propagate .rest into the next call — or use the random monad to handle threading automatically:

# Monadic block — no manual threading
dice: { :random
  a: random.int(6)
  b: random.int(6)
}.[a + b + 2]

result: dice(io.random).value

random.sequence and random.map-m also handle threading:

two-dice: random.sequence([random.int(6), random.int(6)], io.random).value

Shuffling and Sampling

deck: range(1, 53)
hand: random.shuffle(deck, io.random).value take(5)
colours: ["red", "green", "blue", "yellow", "purple"]
two-colours: random.sample(2, colours, io.random).value

Deterministic Seeds

For reproducible output (useful in tests), use --seed on the command line or create a stream from a fixed seed:

eu --seed 42 my-template.eu
stream: random.stream(12345)
x: random.int(100, stream)
# x.value is always the same for seed 12345