Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DSL in Clojure that replaces an object-oriented software solution?

I was wondering wether anyone knew of a concrete example of a DSL in Clojure which replaces the abstraction and readability of a good OO program (written in, say , Java).

I've been trying to take an OO data model (which is "bean" based, with very abstract methods which hide underlying implementations) into a clojure moeity.

I know that "macros" and "higher order functions" exist , however, I've never seen them applied to a real world data set which is easily understood (for example a course-registration system, or a car dealership, or a billing system, or something of the sort, recall the infamous "JPetStore" examples which Hibernate and Ibatis popularized in the last decade).

Does any domain-specific template exist for learning how to model real world systems in Clojure with protocols and higher-order functions?

like image 595
jayunit100 Avatar asked Oct 14 '11 17:10

jayunit100


2 Answers

There are no special templates for DSLs - you just take tools available in the language and try to make it as convenient and close to the domain as possible. Lisp just gives you more tools than other languages do.

For concrete example of nice DSL look at ClojureQL. Initially, SQL was created as DSL for relational databases. And it is very convenient for working from console... but not from the programming language like Java or Clojure. Java came with large ORM frameworks like Hibernate, and Clojure offers simple DSL which is as convenient as original SQL, but works completely as part of the language:

(select (table :users) (where (= :id 5)))

Common thing in Lisp DSLs is using constructs like defsomething. For example, in one book (sorry, I don't remember its name) there's an example of pattern matching in text. Author creates module with a number of matchers like ? for one word, + for one or more words, * for zero or more words and so on. For this purpose he creates macro defmatcher that takes some syntax and adds handler for this syntax to the central registry. This is just abstraction - instead of several repeated operation he introduces single macro telling what he actually wants to do - define matcher. Also this example uses both - macros and high order functions.

So, once again, there's nothing special in Lisp-based DSLs - you just describe domain area with the tools you have in your language, be it Java, Clojure or anything else. Just get used with the language facilities and you will see how it must look like.

UPD. Some "real-world" examples where Lisp-based DSLs are more convenient than, say, OOP:

Domain: car 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: billing system

(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: some web service, that handles requests of several types

(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)))))))

There's nothing special about these examples - you can implement them all in Java or any other language. Though, things like keywords (1st example), higher-order functions (2nd example), macros (all 3 examples) make you code more concise and descriptive.

like image 156
ffriend Avatar answered Oct 30 '22 01:10

ffriend


I don't know if this is what you are looking for but I've read a book about Clojure (Programming Clojure; Pragmatic Programmers) which contains an example of a nice little DSL. You can find the code at https://github.com/stuarthalloway/lancet. Basically lancet is something like make or ant but implemented as a Clojure-DSL.

like image 28
zlajo Avatar answered Oct 30 '22 02:10

zlajo