An algebraic data type (ADT) defines a domain shape with named alternatives, fields, or both. It makes the allowed states and operations visible in code, so a domain model can become a precise, inspectable representation rather than a collection of loosely related calls. ADTs suit complex structures such as trees, graphs, dictionaries, and business models, and they are a central tool for encoding embedded domain-specific languages (eDSLs). section 5.2 section 5.4
A useful design move is to represent each meaningful domain action as an ADT constructor, then keep a script as pure data. An interpreter can traverse that data and connect it to device calls, logging, state, or other effects. This separates a readable scenario from the recursive, stateful, impure implementation required to run it. section 2.2.2 section 1.3.3
Listing 2.1 Domain-specific language for a smart house
type ThermometerName = String type BarometerName = String data Language #1 = ReadThermometer ThermometerName | ReadBarometer BarometerName | ReportTemperature | ReportAtmospherePressure | ClearData type Script = [Language] #2 script :: Script script = [ ReadThermometer "Garage" #3 , ReadThermometer "Near the road" , ReadThermometer "House" , ReadBarometer "Garage" , ReadBarometer "House" , ReportTemperature , ReportAtmospherePressure , ClearData ]
The smart-home language models five actions as alternatives in Language, while Script combines them into an ordered scenario. Each constructor states one permitted instruction and its required data. section 2.2.2
Use ADTs to make architectural boundaries explicit:
- Model a subsystem interface as an ADT plus interpreter when communication must remain functional rather than object-oriented. section 1.3.3
- Keep constructors private when clients should not depend on representation details; expose smart constructors through an abstract module instead. section 3.2.4
- Parameterize a template ADT when one domain shape must support different field-type sets, such as domain, SQLite, and PostgreSQL representations. section 12.1.3
- Use an ADT with continuation fields as the instruction algebra beneath a free-monad language, then provide smart constructors for scripts. section 6.3.1
Keep representation changes behind constructors
A Value type may have BoolValue, IntValue, FloatValue, and StringValue alternatives. If clients pattern-match directly, renaming or adding a constructor breaks their code. Exporting Value while hiding its constructors, and offering functions such as boolValue, stringValue, and intValue, lets the implementation evolve without exposing its internal structure. section 3.2.4
ADTs improve reasoning only when their vocabulary and organization match the domain. A poorly designed eDSL can become restrictive and add accidental complexity; group methods by meaning and scope, separate responsibilities, and preserve the distinction between domain notions and runtime implementation. section 5.4 section 3.1.2




