Atomic Counters in Elm
In Elm, we don’t have the concept of shared mutable state or goroutines. Instead, we’ll simulate the atomic counter behavior using the Elm architecture with a single state and update function. We’ll use the Random
module to simulate concurrent updates.
import Browser
import Html exposing (Html, div, text)
import Random
import Task
-- MODEL
type alias Model =
{ counter : Int
}
init : () -> (Model, Cmd Msg)
init _ =
( { counter = 0 }
, generateUpdates
)
-- UPDATE
type Msg
= Increment
| Complete
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Increment ->
( { model | counter = model.counter + 1 }
, Cmd.none
)
Complete ->
( model
, Cmd.none
)
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.none
-- VIEW
view : Model -> Html Msg
view model =
div []
[ text ("Counter: " ++ String.fromInt model.counter)
]
-- COMMANDS
generateUpdates : Cmd Msg
generateUpdates =
List.range 1 50
|> List.map (\_ -> generateThousandUpdates)
|> Cmd.batch
generateThousandUpdates : Cmd Msg
generateThousandUpdates =
List.range 1 1000
|> List.map (\_ -> Random.generate (\_ -> Increment) Random.bool)
|> Cmd.batch
|> Task.perform identity
-- MAIN
main : Program () Model Msg
main =
Browser.element
{ init = init
, update = update
, subscriptions = subscriptions
, view = view
}
In this Elm program:
We define a
Model
with a singlecounter
field.The
init
function sets up the initial state and triggers the generation of updates.We have two types of messages:
Increment
to increase the counter andComplete
(unused in this example but could be used for additional functionality).The
update
function handles theIncrement
message by increasing the counter.The
view
function displays the current counter value.generateUpdates
creates 50 batches of 1000 random update commands, simulating the behavior of 50 goroutines each incrementing 1000 times.generateThousandUpdates
creates 1000 random update commands.The
main
function sets up the Elm application.
To run this program:
- Save it as
AtomicCounter.elm
- Use the Elm compiler to compile it:
elm make AtomicCounter.elm
- Open the resulting
index.html
in a web browser
You should see the counter value displayed, which will be updated to 50,000 almost instantly due to the simulation of concurrent updates.
Note that this is not truly concurrent or atomic in the same way as the original example, but it demonstrates how you might approach a similar problem in Elm’s functional, single-state-tree model.