This is an example of coding a state machine in Elm.
For a better example, see this one: [ https://gist.github.com/rupertlssmith/88946c8d207d7ad64daf4360fef1ac42 ]
This is an example of coding a state machine in Elm.
For a better example, see this one: [ https://gist.github.com/rupertlssmith/88946c8d207d7ad64daf4360fef1ac42 ]
type alias WithContent = | |
{ contentItem : Content } | |
type alias WithSelectedModel = | |
{ contentModel : ContentModel | |
, overlay : Overlay.Model | |
} | |
type alias WithInlineEditor = | |
{ inlineEditorStyle : Animation.State | |
} | |
type Mode | |
= Loading | |
| Explore WithContent | |
| Markdown WithContent WithSelectedModel | |
| Preview WithContent WithSelectedModel | |
| Wysiwyg WithContent WithSelectedModel WithInlineEditor | |
type alias Model = | |
{ mode : Mode | |
, menu : Menu | |
} | |
maybeLoading : Mode -> Maybe Mode | |
maybeLoading state = | |
case state of | |
Loading -> | |
Just state | |
_ -> | |
Nothing | |
-- ... more maybeState functions | |
mapWhenWithContent : (WithContent -> a) -> Mode -> Maybe a | |
mapWhenWithContent func state = | |
case state of | |
Explore content -> | |
Just <| func content | |
Markdown content _ -> | |
Just <| func content | |
Preview content _ -> | |
Just <| func content | |
Wysiwyg content _ _ -> | |
Just <| func content | |
_ -> | |
Nothing | |
-- ... More mapWhen functions | |
updateWhenWithContent : (WithContent -> WithContent) -> Mode -> Maybe Mode | |
updateWhenWithContent func state = | |
case state of | |
Explore content -> | |
func content |> Explore |> Just | |
Markdown content selected -> | |
func content |> (flip Markdown) selected |> Just | |
Preview content selected -> | |
func content |> (flip Preview) selected |> Just | |
Wysiwyg content selected inline -> | |
func content |> (swirll Wysiwyg) selected inline |> Just | |
_ -> | |
Nothing | |
-- ... More updateWhen functions | |
-- State transition functions - these may contain custom logic, unlike the above which area really just boilerplate. | |
toLoading : Mode -> Mode | |
toLoading _ = | |
Loading | |
toExplore : WithContent -> Mode -> Maybe Mode | |
toExplore content state = | |
case state of | |
Loading -> | |
Nothing | |
_ -> | |
Explore content |> Just | |
toMarkdown : WithSelectedModel -> Mode -> Maybe Mode | |
toMarkdown selected state = | |
case state of | |
Loading -> | |
Nothing | |
_ -> | |
mapWhenWithContent | |
(\content -> | |
Markdown content selected | |
) | |
state | |
toPreview : WithSelectedModel -> Mode -> Maybe Mode | |
toPreview selected state = | |
case state of | |
Loading -> | |
Nothing | |
_ -> | |
mapWhenWithContent | |
(\content -> | |
Preview content selected | |
) | |
state | |
toWysiwyg : WithSelectedModel -> WithInlineEditor -> Mode -> Maybe Mode | |
toWysiwyg selected inline state = | |
case state of | |
Loading -> | |
Nothing | |
_ -> | |
mapWhenWithContent | |
(\content -> | |
Wysiwyg content selected inline | |
) | |
state | |
module StateModel | |
exposing | |
( boolToMaybe | |
, (>&&>) | |
, (>||>) | |
, defaultTransition | |
, mapWhenCompose | |
) | |
import Maybe exposing (andThen) | |
import Maybe.Extra exposing (orElse) | |
boolToMaybe : (a -> Bool) -> a -> Maybe a | |
boolToMaybe filter val = | |
if filter val then | |
Just val | |
else | |
Nothing | |
(>&&>) : (a -> Maybe b) -> (b -> Maybe c) -> a -> Maybe c | |
(>&&>) fst snd val = | |
fst val |> andThen snd | |
(>||>) : (a -> Maybe b) -> (a -> Maybe b) -> a -> Maybe b | |
(>||>) fst snd val = | |
fst val |> orElse (snd val) | |
defaultTransition state trans = | |
trans state |> Maybe.withDefault state | |
mapWhenCompose : (c -> d -> Maybe a) -> (a -> d -> Maybe b) -> c -> d -> Maybe b | |
mapWhenCompose mapWhen1 mapWhen2 func state = | |
mapWhen1 func state | |
|> andThen ((flip mapWhen2) state) |
StateModel.elm contains some helper functions.
This shows a data modelling pattern in Elm. The data model (Model) is a product (Mode) of a sum of little products (WithContent, WithSelectedModel, WithInlineEditor). Functions of this model tend to be written as functions of the little products and this allows a good deal of flexibility since the same functions may work in many states.
Larger scale reorganization of the code as the state machine described by the sum (Mode) is changed can often be performed with less changes to the code than might otherwise be needed.