# `Skuld.Comp.Env`
[🔗](https://github.com/mccraigmccraig/skuld/blob/main/lib/skuld/comp/env.ex#L1)

Environment construction and manipulation.

The Env struct carries scope (handlers, leave-scope, transform-suspend,
current-fiber-id) and effect state. Scope is embedded as a `ScopeEnv` sub-struct — mutate
through `Env.*` functions rather than reaching into `env.scope` directly.

## Effect State

Effect state lives exclusively in `env.state` via `put_state/3` and
`get_state/2,3`. This map is the only state bucket that survives across
fiber suspend/resume cycles — the scheduler threads `env.state` through
all fibers in a pool.

Do **not** add arbitrary top-level keys to the `%Env{}` struct itself.
Such keys will be lost during fiber execution because the scheduler only
preserves `scope` and `state` fields. Use `put_state/3` for any value
that needs to survive across suspensions.

# `t`

```elixir
@type t() :: %Skuld.Comp.Env{
  scope: Skuld.Comp.ScopeEnv.t(),
  state: %{required(term()) =&gt; term()}
}
```

The environment struct.

## Fields

- `scope` — scope machinery (evidence, leave_scope, transform_suspend)
- `state` — effect state (Writer accumulators, channel state, etc.)

# `current_fiber_id`

```elixir
@spec current_fiber_id(Skuld.Comp.Types.env()) :: term() | nil
```

Get the current fiber ID from the env's scope, or nil if not in a fiber

# `delete_handler`

```elixir
@spec delete_handler(Skuld.Comp.Types.env(), Skuld.Comp.Types.sig()) ::
  Skuld.Comp.Types.env()
```

Remove a handler for an effect signature

# `get_handler`

```elixir
@spec get_handler(Skuld.Comp.Types.env(), Skuld.Comp.Types.sig()) ::
  Skuld.Comp.Types.handler() | nil
```

Get handler for an effect signature (returns nil if missing)

# `get_handler!`

```elixir
@spec get_handler!(Skuld.Comp.Types.env(), Skuld.Comp.Types.sig()) ::
  Skuld.Comp.Types.handler()
```

Get handler for an effect signature (raises if missing)

# `get_leave_scope`

```elixir
@spec get_leave_scope(Skuld.Comp.Types.env()) :: Skuld.Comp.Types.leave_scope()
```

Get the current leave-scope handler (returns identity if nil)

# `get_scope`

```elixir
@spec get_scope(t()) :: Skuld.Comp.ScopeEnv.t()
```

Get the scope sub-struct (for inspection)

# `get_state`

```elixir
@spec get_state(Skuld.Comp.Types.env(), term(), term()) :: term()
```

Get state for an effect

# `get_state!`

```elixir
@spec get_state!(Skuld.Comp.Types.env(), term()) :: term()
```

Get state for an effect, raising if the key is not present (use-after-cleanup guard)

# `get_transform_suspend`

```elixir
@spec get_transform_suspend(t()) :: Skuld.Comp.Types.transform_suspend()
```

Get the current transform-suspend handler (returns identity if nil)

# `handler_sigs`

```elixir
@spec handler_sigs(Skuld.Comp.Types.env()) :: [Skuld.Comp.Types.sig()]
```

Get all installed handler signatures

# `inside_fiber?`

```elixir
@spec inside_fiber?(Skuld.Comp.Types.env()) :: boolean()
```

Returns true if currently executing inside a fiber

# `new`

```elixir
@spec new() :: Skuld.Comp.Types.env()
```

Create a fresh environment with identity leave-scope and transform-suspend

# `put_current_fiber_id`

```elixir
@spec put_current_fiber_id(Skuld.Comp.Types.env(), term()) :: Skuld.Comp.Types.env()
```

Set the current fiber ID in the env's scope

# `put_state`

```elixir
@spec put_state(Skuld.Comp.Types.env(), term(), term()) :: Skuld.Comp.Types.env()
```

Update state for an effect.

Effect state lives in `env.state` — the only map that survives across
fiber suspend/resume cycles. Use module-specific keys (e.g. module attributes
or struct-based keys) to avoid collisions between effects.

See the moduledoc for guidance on what belongs in `state` vs on the `Env`
struct directly.

# `run_leave_scope`

```elixir
@spec run_leave_scope(Skuld.Comp.Types.env(), term()) ::
  {Skuld.Comp.Types.result(), Skuld.Comp.Types.env()}
```

Run the leave-scope chain on a result

# `with_handler`

```elixir
@spec with_handler(
  Skuld.Comp.Types.env(),
  Skuld.Comp.Types.sig(),
  Skuld.Comp.Types.handler()
) ::
  Skuld.Comp.Types.env()
```

Install a handler for an effect signature

# `with_leave_scope`

```elixir
@spec with_leave_scope(Skuld.Comp.Types.env(), Skuld.Comp.Types.leave_scope()) ::
  Skuld.Comp.Types.env()
```

Install a new leave-scope handler

# `with_scope`

```elixir
@spec with_scope(t(), Skuld.Comp.ScopeEnv.t()) :: t()
```

Replace the scope sub-struct (for initial construction; prefer with_* functions for mutation)

# `with_transform_suspend`

```elixir
@spec with_transform_suspend(t(), Skuld.Comp.Types.transform_suspend()) :: t()
```

Install a new transform-suspend handler

---

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