# `Skuld.Effects.Random`
[🔗](https://github.com/mccraigmccraig/skuld/blob/main/lib/skuld/effects/random.ex#L1)

Random effect - generate random values.

Provides three handler modes:

- **Production** (`with_handler/1`): Uses Erlang's `:rand` module for
  cryptographically suitable random values.

- **Seeded** (`with_seed_handler/2`): Uses a deterministic seed for
  reproducible random sequences - ideal for testing.

- **Fixed** (`with_fixed_handler/2`): Returns values from a fixed sequence,
  cycling when exhausted - useful for specific test scenarios.

## Production Usage

    use Skuld.Syntax
    alias Skuld.Comp
    alias Skuld.Effects.Random

    comp do
      f <- Random.random()
      i <- Random.random_int(1, 100)
      elem <- Random.random_element([:a, :b, :c])
      {f, i, elem}
    end
    |> Random.with_handler()
    |> Comp.run!()
    #=> {0.7234..., 42, :b}

## Seeded Usage (Deterministic)

    # Same seed produces same sequence - reproducible tests
    comp do
      a <- Random.random()
      b <- Random.random()
      {a, b}
    end
    |> Random.with_seed_handler(seed: {1, 2, 3})
    |> Comp.run!()
    #=> {0.123..., 0.456...}  # always the same

## Fixed Usage (Test Scenarios)

    # Return specific values for testing edge cases
    comp do
      a <- Random.random()
      b <- Random.random()
      c <- Random.random()
      {a, b, c}
    end
    |> Random.with_fixed_handler(values: [0.0, 0.5, 1.0])
    |> Comp.run!()
    #=> {0.0, 0.5, 1.0}

## Handler Submodules

- `Random.Seed` - Deterministic seeded random handler
- `Random.Fixed` - Fixed value handler for testing

# `__handle__`

Install Random handler via catch clause syntax.

Config selects handler type:

    catch
      Random -> nil                            # production handler
      Random -> {:seed, seed: {1, 2, 3}}       # seeded handler
      Random -> {:fixed, values: [0.5, 0.7]}   # fixed values handler

# `state_key`

# `with_fixed_handler`

```elixir
@spec with_fixed_handler(
  Skuld.Comp.Types.computation(),
  keyword()
) :: Skuld.Comp.Types.computation()
```

Install a handler that returns values from a fixed sequence.

Delegates to `Random.Fixed.with_handler/2`.

## Options

- `:values` - A list of values to return. For `random()` these should
  be floats 0.0-1.0. For `random_int/2` and `random_element/1`, the
  handler uses these as indices (mod list length).

## Example

    comp do
      a <- Random.random()
      b <- Random.random()
      c <- Random.random()
      {a, b, c}
    end
    |> Random.with_fixed_handler(values: [0.1, 0.5, 0.9])
    |> Comp.run!()
    #=> {0.1, 0.5, 0.9}

# `with_handler`

```elixir
@spec with_handler(Skuld.Comp.Types.computation()) :: Skuld.Comp.Types.computation()
```

Install a random handler using Erlang's `:rand` module.

Uses the default random algorithm seeded from system entropy.
Not deterministic across runs.

## Example

    comp do
      f <- Random.random()
      f
    end
    |> Random.with_handler()
    |> Comp.run!()

# `with_seed_handler`

```elixir
@spec with_seed_handler(
  Skuld.Comp.Types.computation(),
  keyword()
) :: Skuld.Comp.Types.computation()
```

Install a deterministic random handler with a fixed seed.

Delegates to `Random.Seed.with_handler/2`.

## Options

- `:seed` - A seed tuple `{s1, s2, s3}` for the random generator.
  Default: `{1, 2, 3}`.
- `:algorithm` - The random algorithm to use. Default: `:exsss`.

## Example

    comp do
      a <- Random.random()
      b <- Random.random_int(1, 10)
      {a, b}
    end
    |> Random.with_seed_handler(seed: {42, 42, 42})
    |> Comp.run!()
    #=> {0.123..., 7}  # always the same with this seed

---

*Consult [api-reference.md](api-reference.md) for complete listing*
