soma.cell

Basic State Machine

State machines define valid transitions. The compiler enforces them.

Example 061 of the basic Soma programs: a small, commented program that teaches one thing. Every output below was printed by soma 3.2.4 when this page was built.

How it is built

The cell OrderFlow keeps 2 memory slots: orders (Map<String, String>, persistent and consistent) and state_data (Map<String, String>, persistent and consistent). Its state machine order_status starts in draft and allows 5 transitions: draft -> submitted, submitted -> approved, approved -> shipped, shipped -> delivered and * -> cancelled. cancelled and delivered are terminal. Handlers: create (line 31), advance (line 38), status (line 48), valid_next (line 52) and demo (line 56).

Generated from soma describe on this file.

The source

061_basic_state_machine.cell

// ============================================================================
// 061 — Basic State Machine
// ============================================================================
// State machines define valid transitions. The compiler enforces them.
//
// Run:   soma run 061_basic_state_machine.cell demo
// Expect:
//   Created order 1
//   Status: draft
//   Transitioned to: submitted
//   Status: submitted

cell OrderFlow {

    memory {
        orders: Map<String, String> [persistent, consistent]
        state_data: Map<String, String> [persistent, consistent]
    }

    // Define the state machine: only these transitions are allowed
    state order_status {
        initial: draft

        draft -> submitted
        submitted -> approved
        approved -> shipped
        shipped -> delivered
        * -> cancelled        // any state can go to cancelled
    }

    on create(customer: String) {
        let id = to_string(next_id())
        orders.set(id, customer)
        state_data.set(id, "draft")
        return map("id", id, "customer", customer, "status", "draft")
    }

    on advance(id: String, to: String) {
        let customer = orders.get(id)
        if customer == () {
            return response(404, map("error", "order not found"))
        }
        // transition() validates against the state machine
        let result = transition(id, to)
        return result
    }

    on status(id: String) {
        return get_status(id)
    }

    on valid_next(id: String) {
        return valid_transitions(id)
    }

    on demo() {
        let order = create("Alice")
        print("Created order {order.id}")

        let st = get_status("1")
        print("Status: {st}")

        let result = transition("1", "submitted")
        print("Transition: {result}")

        let result2 = transition("1", "approved")
        print("Transition: {result2}")

        let st2 = get_status("1")
        print("Final status: {st2}")

        return "done"
    }
}

What the toolchain says

$ soma check 061_basic_state_machine.cell
✓ All checks passed.
$ soma run 061_basic_state_machine.cell demo
Created order 1
Status: draft
Transition: {"id": "1", "from": "draft", "to": "submitted"}
Transition: {"id": "1", "from": "submitted", "to": "approved"}
Final status: approved
done