LogicControl is an embedded language for orchestrating spaceship control work at the business-logic level. It can define and prepare hardware through Hdl, invoke device operations through DeviceControl, report messages, and keep key–value state. Its central design problem is coordinating those capabilities without making every lower-level language depend on every other one. section 5.2.3 section 8.2.2
A naïve list-based design lets Hdl and DeviceControl continuations return to LogicControl, while LogicControl evaluates their scripts. That enables a flow such as creating a controller, registering a component, reading a sensor, and reporting the result—but creates cyclic language and module dependencies, deeply nested scripts, and poor cohesion. section 5.2.3 section 6.4.2
Listing 5.6 Highly entangled languages
type Hdl = [HdlMethod] #1
data HdlMethod
= SetupController
DeviceName
ControllerName
ComponentPassport
(Controller -> LogicControl) #2
| RegisterComponent
Controller
ComponentIndex
ComponentPassport
type DeviceControl = [DeviceControlMethod] #3
data DeviceControlMethod
= GetStatus
Controller
(Either String Status -> LogicControl) #4
| ReadSensor
Controller
ComponentIndex
(Either String Measurement -> LogicControl) #5
type LogicControl = [LogicControlMethod] #6
data LogicControlMethod
= EvalHdl Hdl #7
| EvalDeviceControl DeviceControl
| Report Message
Inspect the entangled version to see why embedding Hdl and DeviceControl in both directions makes LogicControl scripts and dependencies hard to manage. section 5.2.3
A first improvement makes subordinate languages parameterized by their continuation type. LogicControl remains the top-level language and chooses Hdl LogicControl or DeviceControl LogicControl when nesting them; the subordinate languages no longer name LogicControl themselves. This preserves the scripting experience while separating their modules and responsibilities. section 5.2.4
The fuller design uses free monads. LogicControl becomes Free LogicControlMethod, with smart constructors for operations such as report and store. GADT-based constructors can evaluate Hdl and DeviceControl operations while preserving each operation’s result type, so a script can bind created controllers, read typed sensor results, and turn hardware failures into logic-level failures. section 6.4.2
LogicControl operations establish a hierarchy of responsibilities:
- EvalHdl runs hardware-definition work, such as setting up controllers or registering components. section 5.2.4 section 6.4.2
- EvalDeviceControlMethod brings device commands such as status checks and sensor reads into control logic. section 6.4.2
- Report communicates a message, although its intended reporting mechanism should be made explicit in the interface. section 8.2.2
- Store and Load model mutable key–value state; a simulation may interpret that state with concurrently mutable in-memory structures. section 8.2.2
Booster status and temperature workflows
A control script can create two boosters through Hdl, obtain each controller’s status through DeviceControl, and combine hardware failures into a LogicFailure. Another workflow creates boosters, reads a nozzle temperature, reports an error on failure, or reports the measurements and a confirmation message on success. These scripts keep orchestration in LogicControl while leaving hardware definition and device primitives below it. section 6.4.2 section 8.2.2
