Skuld.Effects.State (skuld v0.1.26)

View Source

State effect - mutable state threaded through computation.

Supports both simple single-state usage and multiple independent states via tags.

Simple Usage (default tag)

use Skuld.Syntax
alias Skuld.Effects.State

comp do
  n <- State.get()
  _ <- State.put(n + 1)
  n
end
|> State.with_handler(0)
|> Comp.run!()
#=> 0

Multiple States (explicit tags)

comp do
  _ <- State.put(:counter, 0)
  _ <- State.modify(:counter, &(&1 + 1))
  count <- State.get(:counter)
  _ <- State.put(:name, "alice")
  name <- State.get(:name)
  {count, name}
end
|> State.with_handler(0, tag: :counter)
|> State.with_handler("", tag: :name)
|> Comp.run!()
#=> {1, "alice"}

Summary

Functions

Install State handler via catch clause syntax.

Get the current state.

Extract the state for the given tag from an env

Get a value derived from the state.

Modify the state with a function, returning the old value.

Replace the state, returning %Change{old: old_state, new: new_state}.

Returns the env.state key used for a given tag.

Install a scoped State handler for a computation.

Functions

__handle__(comp, initial)

Install State handler via catch clause syntax.

Accepts either initial or {initial, opts}:

catch
  State -> 0                          # initial value
  State -> {0, output: fn r, s -> {r, s} end}  # with opts

get(tag \\ Skuld.Effects.State)

Get the current state.

Examples

State.get()           # use default tag
State.get(:counter)   # use explicit tag

get_state(env, tag \\ Skuld.Effects.State)

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

Extract the state for the given tag from an env

gets(f)

@spec gets((term() -> term())) :: Skuld.Comp.Types.computation()

Get a value derived from the state.

Examples

State.gets(&Map.get(&1, :name))              # use default tag
State.gets(:user, &Map.get(&1, :name))       # use explicit tag

gets(tag, f)

@spec gets(atom(), (term() -> term())) :: Skuld.Comp.Types.computation()

modify(f)

@spec modify((term() -> term())) :: Skuld.Comp.Types.computation()

Modify the state with a function, returning the old value.

Examples

State.modify(&(&1 + 1))              # use default tag
State.modify(:counter, &(&1 + 1))    # use explicit tag

modify(tag, f)

@spec modify(atom(), (term() -> term())) :: Skuld.Comp.Types.computation()

put(value)

Replace the state, returning %Change{old: old_state, new: new_state}.

Examples

State.put(42)              # use default tag
State.put(:counter, 42)    # use explicit tag

put(tag, value)

@spec put(atom(), term()) :: Skuld.Comp.Types.computation()

state_key(tag)

@spec state_key(atom()) :: {module(), atom()}

Returns the env.state key used for a given tag.

Useful for configuring EffectLogger's state_keys filter.

Examples

# Only capture State effect data in EffectLogger snapshots
EffectLogger.with_logging(state_keys: [State.state_key(MyApp.Counter)])

# Multiple states
EffectLogger.with_logging(state_keys: [
  State.state_key(:counter),
  State.state_key(:user)
])

with_handler(comp, initial, opts \\ [])

Install a scoped State handler for a computation.

Options

  • tag - the state tag (default: Skuld.Effects.State)
  • output - optional function (result, final_state) -> new_result to transform the result before returning.

Examples

# Simple usage with default tag
comp do
  x <- State.get()
  _ <- State.put(x + 1)
  x
end
|> State.with_handler(0)
|> Comp.run!()
#=> 0

# With explicit tag
comp do
  x <- State.get(:counter)
  _ <- State.put(:counter, x + 1)
  x
end
|> State.with_handler(0, tag: :counter)
|> Comp.run!()
#=> 0

# Include final state in result
comp do
  _ <- State.modify(&(&1 + 1))
  :done
end
|> State.with_handler(5, output: fn result, state -> {result, state} end)
|> Comp.run!()
#=> {:done, 6}

# Multiple states
comp do
  a <- State.get(:a)
  b <- State.get(:b)
  {a, b}
end
|> State.with_handler(1, tag: :a)
|> State.with_handler(2, tag: :b)
|> Comp.run!()
#=> {1, 2}