State, Reader & Writer
View Source< Getting Started | Index | Throw & Bracket >
The three foundational effects for managing context within a computation.
State
Mutable state scoped to a computation. Operations:
x <- State.get() # read current value
_ <- State.put(val) # replace state
_ <- State.modify(fn x -> x + 1 end) # update via function
x <- State.gets(fn s -> s.count end) # read with accessorTagged variants for multiple independent states:
x <- State.get(:counter) # read tagged state
_ <- State.put(:counter, 0)Handler installation:
computation |> State.with_handler(initial_value)
computation |> State.with_handler(0, tag: :counter)The output option transforms the result before returning:
computation |> State.with_handler(0, output: fn result, final_state ->
{result, final_state} # include final state in result
end)Reader
Read-only configuration, scoped to a computation:
config <- Reader.ask() # read current value
val <- Reader.asks(fn c -> c.key end) # read with accessorScoped overrides within a computation:
Reader.local(fn config -> Map.put(config, :timeout, 5000) end, inner_comp)Handler installation:
computation |> Reader.with_handler(%{timeout: 5000, env: :prod})Writer
Append-only log, collected in order:
_ <- Writer.tell(%SomeEvent{}) # append an event
_ <- Writer.tell(:audit, %LogEntry{}) # tagged writerReading and scoping:
log <- Writer.peek() # read current log
Writer.listen(inner_comp) # isolate inner writer
Writer.pass(inner_comp) # isolate, then merge into outer
Writer.censor(inner_comp, &Enum.filter(&1, fn e -> ... end)) # isolate with filterHandler installation:
computation |> Writer.with_handler([])
computation |> Writer.with_handler([], tag: :audit)
computation |> Writer.with_handler([], output: fn result, log ->
{result, Enum.reverse(log)} # log in chronological order
end)State & Environment overview
| Effect | Read | Write | Transform | Tagged | Handler |
|---|---|---|---|---|---|
| State | get/0,1, gets/1,2 | put/1,2 | modify/1,2 | Yes | with_handler(comp, initial, opts) |
| Reader | ask/0,1, asks/1,2 | — | local/2,3 | Yes | with_handler(comp, value, opts) |
| Writer | peek/0,1 | tell/1,2 | listen/1,2, pass/1,2, censor/2,3 | Yes | with_handler(comp, initial, opts) |
All three support the output option for transforming the final result
with handler state, and suspend for decorating ExternalSuspend data
when the computation yields.