Skuld.Effects.Throw (skuld v0.1.13)

View Source

Throw/Catch effects - error handling with scoped catching.

Uses the %Skuld.Comp.Throw{} struct as the error result type, which is intercepted by catch_error via leave_scope.

Architecture

  • throw(error) returns %Throw{error: error} as the result
  • catch_error installs a leave_scope that intercepts %Throw{} results
  • When caught, the recovery computation runs and continues normal flow
  • Normal completion passes through unchanged
  • If recovery re-throws, the error propagates to outer catch handlers

Summary

Functions

Catch errors from a sub-computation.

Default handler - return Throw struct as result (does not call k)

Throw an error - does not resume

Catch and return Either-style result.

Install a scoped Throw handler for a computation.

Functions

catch_error(comp, error_handler)

Catch errors from a sub-computation.

If the sub-computation throws, the error handler is invoked and its result continues through normal flow (the continuation chain). This allows catch to fully recover from errors - subsequent binds will receive the recovery value.

If the recovery computation itself throws, that error propagates through the leave_scope chain to any outer catch handlers.

Normal completion passes through unchanged (no wrapping).

Example

# Transparent recovery - catch fully handles the error
Throw.catch_error(
  risky_computation(),
  fn :not_found -> Comp.pure(:default) end
)
# Returns either the value or :default

# Nested catch - inner catches first, unhandled propagates to outer
Throw.catch_error(
  Throw.catch_error(inner, fn :a -> ... end),
  fn :b -> ... end
)

handle(throw, env, k)

Default handler - return Throw struct as result (does not call k)

throw(error)

@spec throw(term()) :: Skuld.Comp.Types.computation()

Throw an error - does not resume

try_catch(comp)

Catch and return Either-style result.

Wraps both success and error paths for uniform handling:

  • Success: {:ok, value}
  • Error: {:error, error}

Example

result = Throw.try_catch(risky_computation())
case result do
  {:ok, value} -> handle_success(value)
  {:error, err} -> handle_error(err)
end

with_handler(comp)

Install a scoped Throw handler for a computation.

Installs the Throw handler for the duration of comp. The handler is restored/removed when comp completes or throws.

The argument order is pipe-friendly.

Example

# Wrap a computation with Throw handling
comp_with_throw =
  comp do
    result <- risky_operation()
    return(result)
  end
  |> Throw.with_handler()

# Compose with other handlers
my_comp
|> Throw.with_handler()
|> State.with_handler(0)
|> Comp.run(Env.new())