A monadic interface for The Elm Architecture, bridging synchronous state modifications with asynchronous subscriptions via Channels.
This library merges concepts from two community packages:
chrilves/elm-io — the free monad interface for TEAbrian-watkins/elm-procedure — continuation-passing channels and subscriptionsFlow s a is a free monad that describes a computation which can:
sCmds and receive their resultsBatchThe runtime interpreter (Flow.Program) drives these computations inside a standard TEA update loop, so the rest of your Elm app stays unchanged.
With elm-flow, you do not define a custom Msg type or an update function.
Instead, your view handlers and subscriptions emit Flow values directly,
and the library runtime interprets them.
import Flow exposing (Flow)
import Html
import Html.Events
type alias Model =
{ count : Int }
main : Flow.Program () Model Never
main =
Flow.element
{ init = \_ -> ( { count = 0 }, Flow.none )
, view = view
, subscriptions = \_ -> Sub.none
}
view : Model -> Html.Html (Flow Model ())
view model =
Html.button
[ Html.Events.onClick (Flow.modify (\m -> { m | count = m.count + 1 })) ]
[ Html.text ("Count: " ++ String.fromInt model.count) ]Channels connect external event sources (ports, WebSockets, timers) to a Flow pipeline. Use Flow.Channel.connect to build a channel from an Elm subscription port and an optional command port, then pass it to Flow.await (receive one value) or Flow.subscribe (handle values indefinitely).
-- In Ports.elm
port onMessage : (String -> msg) -> Sub msg
port send : String -> Cmd msg
myChannel : Channel Model String
myChannel =
Flow.Channel.connect
(\callback -> Ports.onMessage (\s -> callback s))
(\_ -> Ports.send "subscribe")
listenLoop : Flow Model ()
listenLoop =
Flow.subscribe
(\msg -> Flow.modify (\m -> { m | lastMessage = msg }))
myChannelWhen you have nested state, the optics helpers (try, forAll, over, setAll, via) work with erlandsona/elm-accessors lenses to target sub-fields without manual getter/setter boilerplate.
See the generated documentation for the full API.
| Function | Description |
|---|---|
pure | Lift a plain value into Flow |
lift | Lift a Cmd into Flow |
get / set / modify | Read and write the model |
andThen / map | Sequence and transform computations |
batch / batchM | Run multiple branches |
none | Terminate / no-op |
| Function | Description |
|---|---|
await | Suspend until a Channel delivers one value |
subscribe | Handle every value from a Channel indefinitely |
yield | Force a render cycle before continuing |
async | Fire-and-forget a sub-computation |
| Function | Description |
|---|---|
when | Conditional execution |
bracket_ | Acquire/release resources around a computation |
setting | Temporarily set a Bool lens to True |
locking | Skip execution if a Bool lens is already True |
BSD-3-Clause