liveBook · Manning

Domain-specific language

As explained in Functional Design and Architecture: Examples in Haskell

A domain-specific language is a programming language designed for a particular application domain, including an embedded form hosted within another language.

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

How Functional Design and Architecture: Examples in Haskell covers it

How deep it goes
Develops embedded DSL design through domain modeling, ADTs, organization, and free-monad wrapping for sequential scripts.
Examples
Uses spacecraft temperature-control scripts and a sandwich-construction recipe to illustrate domain-language scenarios and operations.
What it assumes
Assumes a statically typed functional setting and develops eDSL construction with algebraic data types and free monads.
What you can do after
Build it from scratch by modeling domain instructions with ADTs and wrapping sequential eDSL scripts in free monads.
How it connects
Connects DSLs with domain-driven design, algebraic data types, free monads, type-level polymorphism, and interfaces.

Also explained in

Compare how 10 books explain domain-specific language →

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.