A domain-specific language (DSL) expresses the operations and rules of one application domain rather than acting as a general-purpose abstraction. An embedded DSL (eDSL) lives inside a host language: its interface can serve as a formal representation of a domain model, subsystem, or service. The aim is code that exposes business meaning clearly enough to reason about requirements and valid operations. section 2.2 section 3.1.2 section 5.0
Use a DSL when direct calls to devices, servers, databases, or other infrastructure make application logic tightly coupled. Client code can instead build a scenario in domain terms, leaving native calls behind the language boundary. This shifts attention from implementation dependencies to the operations the domain needs. section 1.3.1 section 5.4
A useful DSL design keeps the domain visible while controlling complexity:
- Model the domain first; avoid universal abstractions that obscure its requirements and meanings. section 5.0
- Organize related languages by meaning and scope, separating responsibilities and placing eDSLs in hierarchies where needed. section 5.4
- Use algebraic data types to encode domain structures and make invalid states harder to represent. section 5.1 section 5.4
- Keep scripts natural for domain experts, even when their operations resemble imperative sequences. section 6.5
Temperature-monitoring language
A temperature-monitoring DSL can describe a readable scenario: read an outside thermometer once a second, register each reading, validate bounds, log failures, and raise an alarm. The same behavior can be reorganized into a stream of readings plus a separate validation scenario, showing that domain languages need not preserve one imperative shape. section 3.1.4
For sequential eDSL scripts, a free monad can wrap a domain algebra and provide monadic chaining. A sandwich recipe illustrates the pattern: start a sandwich, add components, and finish it through self-descriptive smart constructors. The underlying algebra records the available domain instructions and their continuations; the script describes construction before any implementation is selected. section 6.3.1 section 6.5
Listing 3.3 Temperature sensor readings scenario
Scenario: readThermometer #1
Description: monitor outside thermometer temperature
Given: outside thermometer @therm
Invocation: once a second
Read @therm, #2
Result: @reading(@time, @temp, @therm)
If @temp < -10C Then #3
register @reading #4
Log @reading #5
Raise alarm "Temperature is too low" #6
Else If @temp > 50C Then #7
register @reading
Log @reading
Raise alarm "Temperature is too high"
Else register @reading #8
Return @reading #9
Inspect a domain-style temperature scenario with readings, conditional bounds, storage, logging, and alarms; it supplies raw material for an external or embedded DSL. section 3.1.4
A DSL is not automatically an improvement. A poorly designed one can become restrictive, annoying, and accidentally complex. Favor a small, expressive interface that matches known requirements, remains extensible, and keeps domain notions distinct from their runtime implementations. section 2.2 section 5.4









