Package

purescript-transit

Repository
m-bock/purescript-transit
License
BSD-3-Clause
Uploaded by
pacchettibotti
Published on
2026-01-10T07:47:43Z
Transit logo

A PureScript library for building fast and type-safe state machines.


CI Pursuit Tutorial Benchmarks

Table of Contents

Features

  • State transitions are specified with a type-level DSL.
  • Compile-time guarantees that state update functions are complete and valid.
  • Automatic state diagram generation
  • State machine graph analysis
  • Optimized for speed

Documentation

  • API Reference on Pursuit.
  • The Tutorial provides a guided introduction to the library, including motivation, context, and comparison to classic approaches.
  • The examples folder demonstrates various use cases.
  • Benchmark results show performance characteristics compared to classic approaches.

Installation

spago install transit

Minimal Example: A Count Down State Machine

Full source code: test/Examples/CountDown.purs

Let's consider a simple count down state machine which is described by the following state diagram:

Count Down state diagram

Types

To implement this state machine with Transit, first we need to define the state and message types as Variants:

type State = Variant
  ( "Idle" :: {}
  , "Counting" :: { count :: Int }
  , "Done" :: {}
  )

type Msg = Variant
  ( "Start" :: { initialCount :: Int }
  , "Tick" :: {}
  , "Reset" :: {}
  )

Then we need to define the state machine transitions as follows. Note that the last transition has 2 possible return states.

type CountDownTransit =
  Transit
    :* ("Idle" :@ "Start" >| "Counting")
    :* ("Done" :@ "Reset" >| "Idle")
    :*
      ( "Counting" :@ "Tick"
          >| "Counting"
          >| "Done"
      )

Update Function

Finally, we write the update function that is checked at compile time against the state machine specification:

update :: State -> Msg -> State
update = mkUpdate @CountDownTransit
  ( match @"Idle" @"Start" \_ msg ->
      return @"Counting" { count: msg.initialCount }
  )
  ( match @"Done" @"Reset" \_ _ ->
      return @"Idle"
  )
  ( match @"Counting" @"Tick" \state _ ->
      let
        nextCount = state.count - 1
      in
        if nextCount == 0 then
          return @"Done"
        else
          return @"Counting" { count: nextCount }
  )

Generate State Diagram

Reflect type-level state machine specification to a term-level representation:

countDownTransit :: TransitCore
countDownTransit = reflectType (Proxy @CountDownTransit)

Generate state diagram or perform other analysis on the state machine's runtime representation:

main :: Effect Unit
main = do
  let
    graph :: GraphvizGraph
    graph = TransitGraphviz.generate countDownTransit identity

  FS.writeTextFile UTF8
    "renders/count-down_graph.dot"
    (Graphviz.toDotStr graph)

Contributing

Contributions are welcome! Please open an issue to report bugs, suggest improvements, or propose new examples to be added.

If you find this project useful, consider buying me a coffee! ☕

Buy Me a Coffee at ko-fi.com