Domain-Specific Languages
Techniques: macros (syntax), data-as-code (interpret s-expression data), reader macros (Common Lisp custom syntax), #lang languages (Racket: full custom languages with their own readers).
Famous Lisp DSLs: the CL loop macro, Racket's Scribble, Clojure's core.async go, Emacs use-package, SQL DSLs (HoneySQL, Postmodern's S-SQL), and build/config DSLs (Guix, Nix-like Scheme configs).
;; Embedded DSL via macros: a state machine
(define-syntax define-state-machine
(syntax-rules (->)
((_ name (state (input -> next) ...) ...)
(define (name current in)
(case current
((state) (case in ((input) 'next) ... (else 'error))) ...
(else 'error))))))
(define-state-machine traffic
(red (timer -> green))
(green (timer -> yellow) (emergency -> red))
(yellow (timer -> red)))
(traffic 'red 'timer) ; green
(traffic 'green 'emergency) ; red;; Data-driven DSLs (Clojure style): describe with data, interpret with functions
(def routes [["/users" {:get :list-users :post :create-user}]
["/users/:id" {:get :get-user}]])
;; Hiccup: HTML as vectors
[:div {:class "card"} [:h1 "Title"] [:p "Body"]];; Common Lisp: an HTML DSL macro (simplified)
(defmacro html (&body forms)
`(with-output-to-string (s)
,@(mapcar (lambda (f) `(format s "~a" ,(render-form f))) forms)))