Classic Approach

Before diving into Transit, let’s first look at how state machines are typically implemented in PureScript using State and Message data types and an update function performing pattern matching on both. This classic approach is familiar to most PureScript developers and serves as a baseline for understanding what Transit improves upon.

States and Message types

To represent our door in code, we need two major types: the states the door can be in, and the actions that can change those states. In PureScript, we define these as simple data types.

data State
  = DoorOpen
  | DoorClosed

data Msg
  = Close
  | Open

🗎 test/Examples/Classic/Door.purs L14-L20

The State type captures the two possible states we saw in the diagram: DoorOpen and DoorClosed. The Msg type represents the two actions: Close and Open. These correspond directly to what we visualized earlier — each state and each transition from the diagram has a corresponding value in these types.

The update function

Now that we have our types, we need a function that takes the current state and a message, and returns the new state. The traditional way to implement this is with a pattern-matching function:

update :: State -> Msg -> State
update state msg =
  case state, msg of
    DoorOpen, Close -> DoorClosed
    DoorClosed, Open -> DoorOpen
    _, _ -> state

🗎 test/Examples/Classic/Door.purs L22-L27

We pattern match on both the current state and the message at once. It could also be written as a nested pattern match. The update function handles the two valid transitions we saw in the diagram: closing an open door and opening a closed door. The catch-all case _, _ -> state handles any invalid combinations (like trying to open an already open door) by returning the current state unchanged.

While this approach works and is straightforward, it has some drawbacks:

↑ Back to top