A Reader Writer State monad stack. This stack cannot fail. Useful for pure computations that need configuration, logging, and mutable state—such as interpreters or parsers.
tell to log.Use RWS when you never need to fail; use Stax.RWSE when you need fail-fast error handling.
Declare small stacks at the top level, then compose them:
type alias Config =
{ step : Int }
type alias State =
{ total : Int }
addStep : RWS Config String State ()
addStep =
ask
|> andThen (\cfg -> modify (\s -> { s | total = s.total + cfg.step }))
|> andThen_ (tell [ "addStep" ])
double : RWS Config String State ()
double =
modify (\s -> { s | total = s.total * 2 })
|> andThen_ (tell [ "double" ])
computation : RWS Config String State ()
computation =
addStep
|> andThen_ double
|> andThen_ addStep
-- runWith { step = 1 } { total = 0 } computation
-- => ( { total = 3 }, [ "addStep", "double", "addStep" ], () )Just use unit () if you don't need a facet of this. For example,
type alias MyStack a = RWS () () () a that would basically do nothing.get, modify, and put the state but it would be unit so uninteresting.ask for the configuration but it would be unit so uninteresting.tell to log but the result would be a list of units which is uninteresting.Construct a stack from a raw function. Low-level; prefer pure, andThen, and the other combinators.
Execute the stack with config and state. Returns (finalState, logs, result).
Same as run but takes config and state first. Pipeline-friendly: runWith config state myStack.
No-op. Useful with andThen_ when you need a unit-producing computation.
Applicative apply. pure f |> andMap a |> andMap b lifts a two-argument function over the stack.
Monadic bind. Chain computations; each step receives the result of the previous.
Chain when the first computation produces (). Cleaner than andThen (\_ -> second).
pure () |> andThen_ (tell [ "Hello" ])Map the result of a stack with knowledge of the config and state.
Lift a two-argument function over the stack. Equivalent to pure f |> andMap a |> andMap b.
Lift a three-argument function over the stack.
Shorthand for andMapping.
map4 f a b c d
-- is equivalent to
pure f |> andMap a |> andMap b |> andMap c |> andMap dShorthand for andMapping.
map5 f a b c d e
-- is equivalent to
pure f |> andMap a |> andMap b |> andMap c |> andMap d |> andMap eExecute a computation only when the condition is true; otherwise do nothing.
when (count > 0) (modify (\s -> { s | count = s.count - 1 }))Execute a computation only when the Maybe has a value.
whenJust (Just 42) (\n -> tell [ "got " ++ String.fromInt n ])Execute a computation only when the Result is Ok.
whenOk (Ok 42) (\n -> tell [ "success: " ++ String.fromInt n ])Run a list of stacks and collect results. Also known as sequence. Equivalent to combineMap identity.
Map each element through the stack and collect results. Also known as traverse.
Like a for loop: run a computation for each element, discarding results.
for_ [ 1, 2, 3 ] (\n -> tell [ "processing " ++ String.fromInt n ])Iterate over a list with an accumulator. Like List.foldl but the step runs in the stack (config, state, logging).
foldM (\acc x -> pure (acc + x)) 0 [ 1, 2, 3 ]Read the configuration as the value. See andModify, andTell, and mapWith for alternatives that avoid separate ask/get.
Read a projection of the configuration. Equivalent to ask |> map f.
Append to the log. All tell output is collected and returned at the end of run.
This convenience function allows you to log based on the result of a prior computation, the configuration, and the current state and then return the original value. So it acts like a kind of sink.
Convenience function to write a single thing.
Read the current state into the value. Prefer modify or andModify when you only need to update.
Read a projection of the state. Equivalent to get |> map f.
Update the state by applying a function. See andModify for a version that also has the prior result and config.
This convenience function supports modifying the state based on the state, the result of a prior computation, and the configuration.
Want to read the configuration and the state all in one fell swoop? This is it.
Lift a computation that works on a child state to work on a parent state. Accepts record-shaped optics compatible with Monocle; Elm's structural typing means any record with get : parent -> child and set : child -> parent -> parent works.
lens = { get = .count, set = \v s -> { s | count = v } }
liftStateLens lens (modify ((+) 1))Lift a computation to work on a parent state when the child may be missing (Optional/AffineTraversal). The first argument runs if the child is missing; it uses the parent state.
A Reader Writer State monad stack. This stack cannot fail. Useful for pure computations that need configuration, logging, and mutable state—such as interpreters or parsers.
tellto log.Use RWS when you never need to fail; use
Stax.RWSEwhen you need fail-fast error handling.