I know that the title is lame, verging on cringe-inducing, but I had to say it; I'm not sorry.
There has been a
few threads of discussion over on
Hacker News about what's wrong with Lisp. The argument seems to hinge on the lack of a literal syntax for "hashes" in lisp the way that there is in python or, in a more appropriate comparison,
clojure. Clojure is great, by the way, and it is certainly deserving of its own post sometime soon. Suffice it to say that the next time I have to write something in Java I think I'm going to write it in clojure instead. Clojure has
great interoperability with Java. Amazingly, there are
fewer parenthesis in the Lisp version of that little GUI program than in the Java version!
But on to the topic of the day. In many languages you can do something like this:
>>> d = {"a":1, "b":2, "c":3}
>>> d
{'a': 1, 'c': 3, 'b': 2}
>>> d['b']
2
You can see that we can explicitly give a representation of that hash that python knows how to parse into the corresponding data structure. Clojure has a very similar literal syntax:
user=> (get {:a 1 :b 2 :c 3} :b)
2
So the complaint is that Common Lisp doesn't have anything like that. Using hashes in CL consists of a bunch of function calls that manage the hash:
CL-USER> (let ((hash (make-hash-table)))
(setf (gethash :a hash) 1)
(setf (gethash :b hash) 2)
(setf (gethash :c hash) 3)
(gethash :b hash))
2
T
There is never any literal representation of the hash, in fact, if we evaluate the name of the hash we'll just get something like this "#<HASH-TABLE :TEST EQL :COUNT 3 {AD11A99}>" Which basically tells the lisp reader to signal an error if the form is read.
But this doesn't have to be so verbose. We can write a really simple reader macro (with a little helper function) that gives us something like what we have in python or clojure above:
(defun ins-hash (h vals)
(if (oddp (length vals))
nil
(if (not (null vals))
(progn
(setf (gethash (first vals) h) (second vals))
(ins-hash h (cddr vals)))
h)))
(set-macro-character #\} (get-macro-character #\)))
(set-dispatch-macro-character #\# #\{
#'(lambda (stream char1 char2)
(let ((items (read-delimited-list #\} stream t)))
(ins-hash (make-hash-table) items))))
With this reader macro I can now write this:
CL-USER> (gethash :b #{:a 1 :b 2 :c 3})
2
T
Lisp now interprets everything between '#{' and '}' as key, value pairs and using the helper function inserts them into a new hash. Cool!