Suppose I have a type Thing
with a state property A | B | C
,
and legal state transitions are A->B, A->C, C->A
.
I could write:
transitionToA :: Thing -> Maybe Thing
which would return Nothing
if Thing
was in a state which cannot transition to A
.
But I'd like to define my type, and the transition functions in such a way that transitions can only be called on appropriate types.
An option is to create separate types AThing BThing CThing
but that doesn't seem maintainable in complex cases.
Another approach is to encode each state as it's own type:
data A = A Thing
data B = B Thing
data C = C Thing
and
transitionCToA :: C Thing -> A Thing
This seems cleaner to me. But it occurred to me that A,B,C are then functors where all of Things functions could be mapped except the transition functions.
With typeclasses I could create somthing like:
class ToA t where
toA :: t -> A Thing
Which seems cleaner still.
Are there other preferred approaches that would work in Haskell and PureScript?
In the FSM, the outputs, as well as the next state, are a present state and the input function. This means that the selection of the next state mainly depends on the input value and strength lead to more compound system performance.
We’ll see that, for a given state diagram, the state encoding method can reduce the power consumption of the FSM or increase its clock frequency. We can use a state diagram to represent the operation of a finite state machine (FSM). For example, consider the state diagram shown in Figure 1.
The lines between these states show which transitions are possible between states and in which direction. These transitions have conditions for when the FSM needs to change between states.
With the Gray code, only one bit changes when moving between adjacent states. As a result, this encoding technique can reduce the power consumption of an FSM. Moreover, the Gray encoding makes the asynchronous outputs of an FSM resilient to glitches.
Here's a fairly simple way that uses a (potentially phantom) type parameter to track which state a Thing
is in:
{-# LANGUAGE DataKinds, KindSignatures #-}
-- note: not exporting the constructors of Thing
module Thing (Thing, transAB, transAC, transCA) where
data State = A | B | C
data Thing (s :: State) = {- elided; can even be a data family instead -}
transAB :: Thing A -> Thing B
transAC :: Thing A -> Thing C
transCA :: Thing C -> Thing A
transAB = {- elided -}
transAC = {- elided -}
transCA = {- elided -}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With