APIState
State
A state effect and its runners.
A computation performing State s reads and replaces one value of type
s; a runner gives it an initial value and returns the final one with the
result. Use run for state that one task owns, and runAtomic when tasks
that inherit the handler update it concurrently. Runtime.Local offers
scoped local cells instead.
StateResult
type StateResult s a = { value : a , state : s }Source
What a runner returns: the action’s value and the state it left.
Fields
Instances:
(Show s, Show a) => Show (StateResult s a)
State
effect State sSource
Access to one value of type s. Each run has its own cell, so nested
runs, even of the same State s, are independent.
Operations
exchange
exchange : a ->{State a} aSource
Replaces the state with next and answers the state it replaced, as one
update.
import State
result = State.run "old" { State.exchange "new" }
result.value == "old"
result.state == "new"
modify
modify : (a -> a) ->{State a} ()Source
Replaces the state with f applied to it, as one update.
import State
(State.run 3 { State.modify { n -> n * 7 } }).state == 21
run
run : a -> (() ->{State a, e} b) ->{e} StateResult a bSource
Runs action with a fresh state cell holding initial, which is
evaluated once, and returns its value with the final state. Other effects
pass through.
Tasks that inherit this handler share its cell. Each operation reads or
writes a complete value, but an update reads and writes separately, so
concurrent updates can overwrite one another; use runAtomic for those.
import State
result = State.run 10 { State.put (State.get () * 2) }
result.state == 20
result.value == ()
runAtomic
runAtomic : a -> (() ->{State a, e} b) ->{e} StateResult a bSource
Runs action like run, but every operation is atomic, including across
tasks that inherit this handler: concurrent update, modify, and
exchange calls never lose one another’s changes. A get followed by a
put is still two operations; combine them into one update.
An update whose state changed while step was running retries step
on the newer state, so step must be pure and may run more than once. The
returned state is the one when action finished; a task that outlives the
runner can still change the cell later without affecting the result.
import State
result = State.runAtomic 1 { State.modify { n -> n + 1 }; State.update { n -> (n * 10, n + 1) } }
result.value == 20
result.state == 3
