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

value

value : aSource

The action’s result.

state

state : sSource

The state when the action finished.

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

get

get : () ->{State s} sSource

The current state.

put

put : s ->{State s} ()Source

Replaces the state with next.

update

update : (s -> (a, s)) ->{State s} aSource

Replaces the state with the second component of step current and answers the first. Under runAtomic, step may run more than once.

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