sql and s-expressions

On one of the Common Lisp projects I worked on (a very typical Web app), I used the CLSQL library to integrate with a Postgres database. CLSQL is itself an opensource version of the SQL package which is part of Lispworks. One of the more interesting features of this library was an s-expression based query language, which emitted SQL query strings behind the scenes. So, for example:

(select [count 1]
        :from '([person])
        :where [and [= [role] +role-programmer+]
                [< [age] 30]))

would emit the following SQL (and actually runs the query):

SELECT COUNT(1) FROM person WHERE (role = 1 AND age < 30)

Nice. Just being able to write the WHERE clause as a readable s-expression makes CLSQL worthwhile. Of course, it does much more than just that.

Anyway, Clojure has a library in clojure-contrib, for integrating with SQL databases using JDBC. But, as you can see from the examples on that wiki page, SELECT, INSERT and UPDATE more or less require hand built SQL query strings. So, I figured I'd try and emulate the CLSQL approach using Clojure macrology. Here's what I was able to do:

(sql-select-stmt "count(1)"
                 :from '(person)
                 :where (sql-and (sql-= 'role +role-programmer+)
                                 (sql-< 'age 30)))

Not as concise as CLSQL (the "sql-" prefix interrupts the flow), but perhaps the best we can do, considering Clojure doesn't have programmable reader macros (at least not without serious hackery). CLSQL cleverly uses reader macros to do interesting things with expressions which are inside square brackets, like turning [or ...] into (sql-or ...), and [a-table-name] into "atablename" etc.

Incidentally, sql-select-stmt doesn't run the query, just generates the query string, which can be passed to with-results, like so:

(with-results rs
  (sql-select-stmt "count(1)"
                   :from from
                   :where where)
  (:count (first rs)))

The code for the sql macros is a bit long to insert here, so I'm thinking I'll create a cynojure repo on github, and put all the various bits of clojure code I create in there. I'll post about that separately.

Peace.

welcome to cynojure

Welcome to cynojure – a blog about clojure – a modern Lisp implementation.

I've been hacking Lisp, professionally and as a hobbyist, for about eighteen years now. Starting with elisp and Scheme, and then Common Lisp for the past eight years. At the risk of importing my CV into this post, I've worked in Smalltalk, Objective-C, Java; even some Cadence SKILL. More recently, I got to work on a reasonably extensive project in Erlang. Before you write me off as a mono-lingual snob, let me assure you I've had a fair amount of experience with C and its derivative family of languages as well. I just happen to be a bigger fan of Lisp, and functional programming in general; which leads me to clojure.

I first heard about clojure a year back, and was very impressed with the design motivations of its creator, Rich Hickey. A pure functional Lisp with immutable data structures, STM, actors … and, efficient Java interop! Sounded too good, so I had to check it out. Since then, I've been following the development of the language and its libraries, read the Programming Clojure book, and played with it enough to be somewhat productive.

And, this week (May 4, 2009) Rich Hickey formally announced the release of Clojure 1.0, which is great news. Congratulations to Rich and all the other contributors. To mark this major milestone in Clojure's history, and to add my own little bit to its growth, I decided to blog about my experiences with clojure as I learn and apply it. Hopefully, my experiences will be of some use or entertainment to others :)

Happy hacking.

PS: About the name - cynojure is a play (in keeping with clojure tradition) on the word cynosure, which according to WordNet has the following meanings:

cynosure

something that provides guidance (as Polaris guides mariners)

something that strongly attracts attention and admiration

Perhaps a bit grandiose, but I thought it was suitable.

keyword args in clojure

I like the keyword args support in Common Lisp. So, when I learned that clojure didn't support keyword args in the base language, I was a bit disappointed. But, with clojure's support for destructuring and macros, it should be easy to build keyword args … right?

Rich Hickey posted a simple example on the clojure mailing list, which I adapted slightly to my taste:

(defmacro defun [sym args & body]
  (let [[pargs [_ & kargs]] (split-with (fn [x] (not (= x '&key))) args)
        gkeys (gensym "gkeys__")
        letk (fn [k]
               (let [[nm val] (if (vector? k) k [k])
                     kname (keyword (name nm))]
                 `(~nm (or (~gkeys ~kname) ~val))))]
    `(defn ~sym [~@pargs & k#]
       (let [~gkeys (apply hash-map k#)
             ~@(apply concat (map letk kargs))]
         ~@body))))

After which:

(defun foo [a b &key c [d 5]]
  [a b c d])

user> (foo 1 2 :c 10)
[1 2 10 5]

Joy.