Antra

Standardbibliothek

Antra::Random

import Antra::Random

Pseudozufallszahlen fuer Antra auf Basis eines seed-threadenden RNG-Modells.

Der Grundtyp in diesem Paket ist ein RNG-Wert der Form:

|seed| -> [wert, neuer_seed]

Dieser RNG-Typ kann mit step(...), sample(...), map_gen(...) und bind(...) kombiniert werden.

Wenn du daraus einen echten gen fn-Generator fuer take(...), for ... in ... oder next(...) machen willst, benutze stream(rng, seed).

Deterministisch (gleicher Seed → gleiche Ausgabe):

my s = Random.seed(42)
my r = Random.step(Random.int(1, 6), s)
println(r[0])

Als echter Sprach-Generator:

my g = Random.stream(Random.int(1, 6), Random.seed(42))
println(take(g, 5))

Nicht deterministisch (zeitbasierter Seed):

my roll = Random.sample(Random.int(1, 6))
println(roll)

Überblick#

Fuer deterministische Pseudozufallswerte mit explizitem Seed.

Der Grundtyp in Antra::Random ist zunaechst kein Sprach-Generator, sondern ein seed-threadender RNG-Wert dieser Form:

|seed| -> [wert, neuer_seed]

Darum liefern Funktionen wie int(...), float(...) oder bool() nicht direkt etwas, ueber das du mit for ... in ... iterieren kannst. Stattdessen arbeitest du zuerst mit step(...) oder sample(...):

import Antra::Random as Random

my seed = Random.seed(42)
my [roll, next_seed] = Random.step(Random.int(1, 6), seed)
println(roll)

Fuer enge Hotpaths gibt es auch einen direkten Fast-Path ohne vorherigen Generator-Closure-Bau:

import Antra::Random as Random

my [roll, next_seed] = Random.int_step(1, 6, Random.seed(42))
println(roll)

Wenn du daraus einen echten Sprach-Generator machen willst, gibt es den Adapter stream(...):

import Antra::Random as Random

my rolls = Random.stream(Random.int(1, 6), Random.seed(42))
println(take(rolls, 5))

Die praktische Trennung ist also:

  • int(...), float(...), bool(), uniform(...), weighted(...): bauen RNG-Werte
  • step(...) und sample(...): fuehren solche RNG-Werte aus
  • stream(...): macht daraus einen echten gen fn-artigen Datenstrom fuer take(...), for ... in ..., map(...) oder filter(...)

Funktionen#

fn bind(rng, f)

Chains RNG values, where f receives the produced value and returns another RNG value.

Example:

import Antra::Random as Random

my chained = Random.bind(Random.int(1, 3), |n| -> Random.int(n, n + 10))
println(Random.step(chained, Random.seed(42))[0])
fn bool()

Returns an RNG value for true or false with equal probability.

Example:

import Antra::Random as Random

println(Random.step(Random.bool(), Random.seed(42))[0])
fn choose(a, b)

Returns an RNG value that chooses between a and b with equal probability.

fn constant(val)

Returns an RNG value that always produces val and does not consume seed state.

Example:

import Antra::Random as Random

println(Random.step(Random.constant(99), Random.seed(42))[0])
fn fixed_list(rng, n)

Returns an RNG value that produces a list with exactly n values.

Example:

import Antra::Random as Random

println(Random.step(Random.fixed_list(Random.int(1, 6), 5), Random.seed(42))[0])
fn float(from, to)

Returns an RNG value for floating-point numbers in [from, to).

Example:

import Antra::Random as Random

println(Random.step(Random.float(0.0, 1.0), Random.seed(42))[0])
fn int(from, to)

Returns an RNG value for integers in [from, to].

Example:

import Antra::Random as Random

println(Random.step(Random.int(1, 6), Random.seed(42))[0])
fn int_step(from, to, s)

Fast path for integer sampling without constructing an RNG closure first.

Returns [value, next_seed] like step(int(from, to), seed), but is better suited for tight interpreter loops.

Example:

import Antra::Random as Random

my [roll, next_seed] = Random.int_step(1, 6, Random.seed(42))
println(roll)
fn list_gen(rng)

Returns an RNG value that produces a list with random length from 0 to 32.

fn map_gen(rng, f)

Maps the produced value of an RNG with f.

Example:

import Antra::Random as Random

my doubled = Random.map_gen(Random.int(1, 6), |n| -> n * 2)
println(Random.step(doubled, Random.seed(42))[0])
fn sample(rng)

Executes an RNG value with a time-based seed.

This is convenient, but intentionally not deterministic.

Example:

import Antra::Random as Random

println(Random.sample(Random.int(1, 6)))
fn seed(n)

Returns a deterministic seed value.

Example:

Random.seed(42)
fn shuffle(list)

Returns an RNG value that shuffles a list with Fisher-Yates.

Example:

import Antra::Random as Random

println(Random.step(Random.shuffle([1, 2, 3]), Random.seed(42))[0])
fn step(rng, s)

Executes an RNG value with an explicit seed.

Returns [value, next_seed].

Das ist die niedrigste, explizite Form der API: Du bekommst nicht nur den aktuellen Wert, sondern auch den naechsten Seed zurueck. Wenn du dieselbe Zufallsquelle weiterlaufen lassen willst, uebergibst du genau diesen next_seed an den naechsten step(...)-Aufruf.

Example:

import Antra::Random as Random

my [roll, next_seed] = Random.step(Random.int(1, 6), Random.seed(42))
println(roll)

my [next_roll, third_seed] = Random.step(Random.int(1, 6), next_seed)
println(next_roll)
gen fn stream(rng, s)

Turns an RNG value plus a seed into a real gen fn-style generator.

Use this when you want to consume random values with take(...), for ... in ..., map(...) or filter(...).

Example:

import Antra::Random as Random

my rolls = Random.stream(Random.int(1, 6), Random.seed(42))
println(take(rolls, 5))

for roll, i in Random.stream(Random.int(1, 6), Random.seed(42)) {
    last if i >= 2
    println(i <> ":" <> roll)
}
fn time_seed()

Returns a time-based seed for non-deterministic sampling.

Example:

Random.time_seed()
fn uniform(list)

Returns an RNG value that picks uniformly from a list.

fn weighted(pairs)

Returns an RNG value for weighted choice.

pairs has the form [[weight, value], ...].

Quelle dieser Seite