Non ci sono modelli speciali per DSL - basta prendere strumenti disponibili nella lingua e tenta di farlo più comodo e vicino al dominio come possibile. Lisp ti offre solo più strumenti di quelli di altre lingue.
Per esempio concreto di bello look DSL allo ClojureQL. Inizialmente, SQL è stato creato come DSL per i database relazionali. Ed è molto conveniente per lavorare dalla console ... ma non dal linguaggio di programmazione come Java o Clojure. Java è venuto con grandi quadri ORM come Hibernate, e Clojure offre semplici DSL, che è così conveniente come SQL originale, ma funziona in modo completamente come parte del linguaggio:
(select (table :users) (where (= :id 5)))
cosa comune in Lisp DSL sta usando costrutti come defsomething
. Ad esempio, in un libro (mi spiace, non ricordo il suo nome) c'è un esempio di corrispondenza del modello nel testo. L'autore crea un modulo con un numero di elementi di corrispondenza come ?
per una parola, +
per una o più parole, *
per zero o più parole e così via. A questo scopo crea la macro defmatcher
che richiede una certa sintassi e aggiunge il gestore per questa sintassi al registro centrale. Questa è solo astrazione: invece di molte ripetute operazioni, introduce una macro singola che dice cosa vuole realmente fare: definire il matcher. Anche questo esempio usa entrambe le macro e le funzioni di alto ordine.
Così, ancora una volta, non c'è niente di speciale in DSL Lisp-based - semplicemente descrivere zona dominio con gli strumenti che hai nella tua lingua, sia Java, Clojure o qualsiasi altra cosa. Basta abituarsi con le strutture linguistiche e vedrai come deve essere.
UPD. Alcuni esempi "mondo reale" in cui DSL Lisp-based sono più convenienti rispetto, ad esempio, OOP:
Domain: auto dillership
(defcar my-cool-car :wheels 4, :doors 2, :color red) ;; in Java you need Factory
(def car1 (make-car my-cool-car)) ;; and lots of methods to
;; add features to cars and
;; cars to factory
Domain: il sistema di fatturazione
(transaction ;; in Java you cannot create wrapping constructs
(withdraw account1 100) ;; so you have to use inheritance, annotations, etc.
(put account2 100)) ;; which is much more code
Domain: qualche servizio web, che gestisce richieste di diversi tipi
(defhandler :show-all (fn [params] ...)) ;; adds defined function to the
(defhandler :find-best (fn [params] ...)) ;; map of :message-type -> function
...
(defn handle [message]
(let [msg-type (:type message), msg-params (:params message)]
(if (contains? *handlers* msg-type)
((*handlers* msg-type) msg-params)
(throw (Exception. (concat "No handler for type" (:type message)))))))
Non c'è cosa speciale su questi esempi: puoi implementarli tutti in Java o in qualsiasi altra lingua. Tuttavia, cose come le parole chiave (1 ° esempio), le funzioni di ordine superiore (2 ° esempio), le macro (tutti e 3 gli esempi) rendono il codice più conciso e descrittivo.
... lancet è un DSL, ma non è proprio un problema del "mondo reale" in quanto la maggior parte dei programmatori non ha mai provato a scrivere un sistema del genere: controlla il buon vecchio 'google: applicazione jpetstore .... – jayunit100