Implementation using Transit
State and message types
Nothing special here. We define the state and message types like we did in the previous examples. By using Variants, we have no constraint on how the labels are named; we can use any type-level string we want: numbers, lowercase letters, etc. Traditional ADTs wouldn’t give us this flexibility.
type State = Variant
( "1" :: {}
, "2" :: {}
, "3" :: {}
, "4" :: {}
, "5" :: {}
)
type Msg = Variant
( "a" :: {}
, "b" :: {}
, "c" :: {}
, "d" :: {}
, "e" :: {}
, "f" :: {}
, "g" :: {}
, "h" :: {}
)🗎 test/Examples/HouseSantaClaus.purs L27-L44
Type-level specification
The transit specification follows the same pattern as in the previous example.
type SantaTransit =
Transit
:* ("1" |< "a" >| "2")
:* ("2" |< "b" >| "3")
:* ("3" |< "c" >| "5")
:* ("5" |< "d" >| "4")
:* ("4" |< "e" >| "1")
:* ("1" |< "f" >| "3")
:* ("2" |< "g" >| "4")
:* ("3" |< "h" >| "4")🗎 test/Examples/HouseSantaClaus.purs L46-L55
The Update Function
Until now, we have always manually defined the update function. In
most cases this will be the way to go. But you may have noticed that in
some cases this is sheer boilerplate. We can let the compiler generate
the update function for us by using the mkUpdateAuto
function. This works if the following conditions are met:
- There are no conditional transitions in the state machine.
- State transitions don’t change the type of the state payload.
Both conditions are met in our case, so we can use
mkUpdateAuto to generate the update function for us. We
could have used it in the Door example and the Bridges of Königsberg
example as well.
update :: State -> Msg -> State
update =
mkUpdateAuto @SantaTransit