Wednesday, November 12, 2008

Getting started with Clojure

Clojure Logo Whenever I finish a major piece of work (Tapestry 5.0.16, in this case), I like to try learning some new things before I start the next major phase. I've got a pent-up stack of things to try and learn, but foremost of these is Clojure.

I've always been fascinated with Lisp, though I last used it in college, nearly 20 years ago. Still, even then, I considered it a kind of litmus test ... if you didn't "get" Lisp (and, especially, recursion) you really were limited in how far you could go in this industry.

In any case, Clojure is something new; it's a Lisp, meaning it is similar to Common Lisp ... but it is not a common Lisp, it's a new functional language designed for high concurrency but also full interoperation with the JVM. In other words, it's like Scala, a new language explicitly tied to the JVM, but it goes the opposite direction in terms of the type system.

What's attracting me to it, rather than Scala (or Haskell for that matter) is the syntax. Scala's type system has been pretty daunting for me, and its syntax does reflect that. Lisp has the simplest syntax you can imagine.

The fact that Clojure supports Erlang-ish agents as well as Software Transactional Memory means that it is built for very high concurrency applications ... but you can always escape down to the nitty gritty Java level.

In other words, I've been buying into the "less-is-more" philosophy of Clojure vs. the "more-is-more" philosophy of Scala. Further, it's combining nearly 50 years of Lisp concepts with the ubiquitous and fast JVM platform, and embracing relatively new ideas to support concurrency, with a target on the dozens or hundreds of cores typical machines are expected to have in just a few years.

I've started reading Stuart Halloway's book, Programming Clojure. Fun read so far, Stuart's style is very approachable.

However, Clojure is right on the bleeding edge, and getting an environment set up is still a bit of an exercise left up to the reader.

To keep things organized, I created a /usr/local/clojure directory (I'm on a Mac) to keep the various Clojure resources stable and centrally located.

First is Clojure itself. There are downloads available, but Stu's book is already ahead of the latest download, so you'll want to build it yourself.

svn co https://clojure.svn.sourceforge.net/svnroot/clojure/trunk clojure
It builds with Maven in a few seconds. It's relatively small too .. 461K, and that includes a private copy of ASM. Just build with mvn clean install and copy the JAR file to /usr/local/clojure/clojure.jar.

Next is the standard contrib library for Clojure; this is needed for many of the examples in Stu's book. I haven't found an easy download for this yet, so I downloaded the source and built it myself:

svn co https://clojure-contrib.svn.sourceforge.net/svnroot/clojure-contrib/trunk clojure-contrib 

This one has an Ant build. It's really just a JAR file of Clojure script files. I recommend building it yourself, but if you are in a rush, I've placed a copy of clojure-contrib.jar on my website for download. You can imagine that it will be quickly out of date.

Next up is Emacs. Clojure syntax is very close to Lisp syntax, and nothing edits Lisp syntax better than Emacs, which is itself written in its own Lisp dialect.

I haven't used Emacs in anger in years, and then it was a bit of a monster (a version written in PL/1!). In fact, its probably been long enough that I won't remember the wrong, broken key bindings of the PL/1 version. In any case, I'm on a Mac, so Emacs is built in ... but there's a better alternative, Aquamacs Emacs which is striving for a best-of-both worlds approach. If you are on windows, Cygwin (as usual) is the way to go, and there's a lot of discussion on the Clojure Programming Wiki Page as well.

Next up we need to set up a Clojure mode for Eclipse. This is available at http://clojure.codestuffs.com/. Download, unpack, and copy the files to /usr/local/clojure as well.

The last step is to modify Emacs to load the Clojure mode. The following can go into ~/.emacs for a traditional Emacs, or ~/Library/Preferences/Aquamacs Emacs/Preferences.el for AquaEamcs:


(setq inferior-lisp-program
                                        ; Path to java implementation
      (let* ((java-path "java")
                                        ; Extra command-line options
                                        ; to java.
             (java-options "-Xms100M -Xmx600M")
                                        ; Base directory to Clojure.
                                        ; Change this accordingly.
             (clojure-path "/usr/local/clojure/")
                                        ; The character between
                                        ; elements of your classpath.
             (class-path-delimiter ":")
             (class-path (mapconcat (lambda (s) s)
            ; Include all *.jar files in the clojure-path directory
        (file-expand-wildcards (concat clojure-path "*.jar"))
                                    class-path-delimiter)))
        (concat java-path
                " " java-options
                " -cp " class-path
                " clojure.lang.Repl")))

;; Require clojure-mode to load and associate it to all .clj files.

(add-to-list 'load-path "/usr/local/clojure")

(require 'clojure-mode)

(setq auto-mode-alist
      (cons '("\\.clj$" . clojure-mode)
            auto-mode-alist))

Of course, you'll need to modify this to reflect the proper path you've been placing all these files.

Note: Stu's book mentions adding the sources from the book to the classpath as well; you can see in the above code where a list of classpath entries is being assembled, and you could add "/path/to/book/source" into the list.

When you next restart Emacs, you'll want to find a Clojure file to activate Clojure Mode ... any file with a .clj extension will activate Clojure Mode. Then C-c C-z will launch Clojure.

Lots to learn, lots to learn.

2 comments:

  1. "When you next restart Emacs, you'll want to find a Clojure file to activate Clojure Mode"

    This isn't Eclipse - there's no need to restart emacs to get this new behaviour ... you can either evaluate a sexp with C-x C-e or M-x eval-region to eval a region (remember C-h ? for help ;)

    ReplyDelete
  2. "you can either evaluate a sexp with C-x C-e or M-x eval-region to eval a region"

    Or you can M-x eval-buffer to eval the entire buffer.

    ReplyDelete

Please note that this is not a support forum for Tapestry. Requests for help will be deleted. Please subscribe to the Tapestry user mailing list if you are in need of support, or contact me directly for professional (for pay) support.

Spammers: Don't bother. I delete your comments and it's a waste of time for both of us. 垃圾邮件发送者:不要打扰。我删除您的评论和它的时间对我们双方的浪费