liveBook · Manning

Hdl

As explained in Functional Design and Architecture: Examples in Haskell

Hdl is a book-specific embedded domain-specific language for defining hardware devices and registering their components in the Andromeda control software.

Hdl is an embedded domain-specific language for describing compound hardware devices in Andromeda. Its earliest form is a list of component definitions: each entry assigns a component passport to an index within a device. A passport carries vendor, name, physical GUID, and component class, while the index identifies the installed part such as a nozzle sensor or controller. The result is a declarative hardware schema rather than a live device or its stateful implementation. section 3.3.2 section 5.2.1

Listing 3.9 HDL for device definitions
module Andromeda.Hardware.Common where         #1
  
type PhysicalGuid  = String                    #2
type ComponentName = String                    #3
  
data Parameter      = Temperature | Pressure   
data ComponentClass = Sensors | Controllers
type Vendor         = String
  
data ComponentPassport = ComponentPassport
  { componentClass  :: ComponentClass
  , componentName   :: ComponentName
  , componentGuid   :: PhysicalGuid
  , componentVendor :: Vendor
  }
 
  
module Andromeda.Hardware.Hdl where            #4
  
import Andromeda.Hardware.Common               #5
  
type ComponentIndex = String
  
data ComponentDef
  = Sensor     ComponentPassport ComponentIndex Parameter 
  | Controller ComponentPassport ComponentIndex
  
type Hdl = [ComponentDef]                      #6

The initial algebra shows Hdl as a list of sensor and controller definitions, each combining a passport with its device-local index. section 3.3.2

A naive representation duplicates component-kind information: a definition can say “controller” while its passport says “sensor,” or a thermometer can be assigned a pressure measurement. Move sensor measurement information into the passport’s component class, where vendor data defines what the component actually is. Then reduce each Hdl entry to an index and passport. This removes redundant constructors and makes a device declaration a straightforward list of installed vendor components. section 4.1.2 section 4.1.3

Keep hardware declarations dependable by separating responsibilities:

  • Store vendor-specific names, GUIDs, classes, and capabilities in reusable component passports rather than scattering magic strings through device definitions. section 4.1.2
  • Hide inconsistent internal representations when necessary and expose smart constructors that always pair a sensor or controller definition with the matching class. section 3.3.2
  • Interpret an Hdl schema against a map of real vendor components, validating that every referenced passport is available before inserting the part into the device map. section 4.1.3

Declaring boosters

A boosters schema can register temperature and pressure sensors at nozzle indexes and a controller at a controller index. Multiple entries may reuse the same passport when the same vendor component is installed more than once. Interpretation resolves each passport against available implementations, then builds a device dictionary keyed by component index; missing vendor components become validation errors. section 4.1.3

Hdl also evolves from a static schema into a procedural setup language. SetupController creates a controller handle, and RegisterComponent attaches components to that handle. The action list still describes work rather than performing it, but its ordering now matters: registering before setup, using an unknown controller name, or repeating components creates undefined or ambiguous behavior. Continuations can pass a controller produced by setup into later actions, turning a flat list into a tree-shaped script that can also read sensors and report results. section 5.2.2

That broader script language is too responsible for device definition, hardware interaction, and reporting at once. Split those concerns into Hdl, DeviceControl, and LogicControl. Direct nesting initially creates cyclic dependencies, so parameterized ADTs abstract Hdl’s next step and let the top-level LogicControl language choose the enclosing context. Hierarchical free eDSLs retain this hierarchy while making lower-level languages genuinely decoupled and allowing typed results to return from Hdl operations. section 5.2.3 section 6.4.2

In the resulting architecture, Hdl forms the boundary between business-level hardware definitions and device machinery. It deliberately exposes device definition rather than ship control; LogicControl coordinates higher-level behavior, while DeviceControl performs reads and status operations. This boundary supports low coupling between a descriptive schema and implementations that may require connections, state, or concurrent actors. section 4.2.1 section 6.4.2

How Functional Design and Architecture: Examples in Haskell covers it

How deep it goes
Develops list-based ADTs through smart constructors, interpreters, continuations, parameterization, and hierarchical free eDSL composition.
Examples
Uses booster definitions, vendor component passports, invalid component declarations, setup scripts, and sensor-reading scripts.
What it assumes
Assumes familiarity with Haskell-style algebraic data types while developing smart constructors, continuations, and parameterized ADTs incrementally.
What you can do after
Build it from scratch as a typed hardware-definition eDSL, then compose it with control languages and interpreters.
How it connects
Connects algebraic data types, smart constructors, interpreters, continuations, DeviceControl, LogicControl, and free monads.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Design and Architecture: Examples in Haskell. The section links point to the parts of the book it draws on.