web analytics

Clojure and Emacs sitting in a tree

May 11, 2014

I’ve been meaning to learn a lisp, more specifically common lisp. Common lisp is wonderful, don’t get me wrong, but the problem is if I don’t use it on a daily basis I keep forgetting the details. I always keep a Slime REPL open on my Emacs session, but practice makes perfect and I definitely could use more practice. My first approach was to look for an opportunity to introduce common lisp in my day job, however I struggled greatly with lisp development.

When I talk about development as opposed to coding, I mean access to third party support libraries, tooling, integration with existing projects, project management, dependency management, testing and surely some other things that are important but I’m missing. A good starting point for common lisp is the site Articulate Common Lisp. They show you how a project is laid out, how quicklisp fits in the picture, as well as some examples. There’s still something missing.

For a (not so) hypothetical example: say you have a requirement to schedule tasks to be executed sometime in the future. It can be in minutes, hours, days, weeks, etc. Also it needs to support recurrence: this task is to be executed every two weeks, or each first of the month. Seems like a perfect example to hone our lisp chops. The requirement is concise, self contained (tasks go in, are scheduled, and then executed), and can be deployed as an independent tool.

In Common Lisp
There’s no standard way of doing this in Common Lisp, so we need to resort to an implementation specific solution. That’s not a huge problem since I don’t have any restriction in which lisp I use, so for SBCL there’s Clon. From the description:

Clon is a task scheduler library much like cron for lisp that is implemented as a shallow layer on top of SBCL timers.

Sounds like what we need. So we fire up quicklisp, search for the library and finally load it:

(ql:system-apropos "clon")
#SYSTEM clon / clon-20110320-git / quicklisp 2014-04-25
#SYSTEM clon-test / clon-20110320-git / quicklisp 2014-04-25
#SYSTEM clonsigna / clonsigna-20120909-git / quicklisp 2014-04-25
#SYSTEM com.dvlsoft.clon / clon-1.0b23 / quicklisp 2014-04-25
(ql:quickload "com.dvlsoft.clon")

How do we use the library? Good luck. There’s no documentation beyond the source code, a few examples and a readme. That’s certainly enough for some, but for others it is woefully inadequate. What’s more, is this library production ready? I couldn’t make it work. I’m sure most of it is caused by my own inexperience with the whole environment, but that’s exactly my point: there’s no clear, easy path for going from zero to hero. Another quicklisp loaded library, drakma (a http client), I was able to use perfectly fine.

In Clojure
Searching for a scheduling library in Clojure turns Quartzite. That’s good news, because Quartz (upon which Quartzite is based) is a mature scheduling library. While you can and are encouraged to open a Clojure REPL and start hacking away, in Clojure things are organised around projects. This is both a good thing and a bad thing. The good thing is with a project organisation you automatically know things fit, how to add dependencies, how to manage them. The bad thing is well, you need to create a project.

To ease the bad thing the Clojure community came up with Leiningen, advertised as the easiest way to use Clojure. Once we have a leiningen created project, we may add dependencies via its project.clj file:

(defproject clojure-noob "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]
[clojurewerkz/quartzite "1.1.0"]])

Here Common Lisp takes the lead. While it’s easy enough to create a project in Clojure and add dependencies to it, if a JVM was already running you would need to restart it to pick up the new dependency. So if you had a REPL open, you will be required to close it and start a new one. Bummer, especially if you contrast it with quicklisp’s (ql:quickload “something”) mechanism. Pomegranate promises to tame the Java Classloader dragon, but we won’t go into it at this point. Assuming you have your dependency set and the REPL open:

(qs/initialize)
(qs/start)

Bam! you’ve got yourself a scheduler. With a little more effort you have a complete scheduler able to accept cron style schedules, or calendar style schedules, or both. With even more effort you can have your scheduler exposed through the network, accepting commands and executing tasks on schedule.

Clojure and Emacs
At this point I already decided to go with Clojure. It doesn’t hurt either that we already have some investment in the JVM (albeit in the Java language). If you’re at the same point and would like to know how to get Clojure up and running in Emacs, the same easy way you can use Common Lisp with Slime, read on.

I use Cask for package management. Cask is great for dependency management in Emacs. It allows you to define a list of repositories, a list of dependencies and then run Cask at it fetches all your dependencies, compiles them and you’re done. If you are like me constantly trying out new packages and messing up your Emacs configuration, Cask is a godsend. Anyway if you don’t use Cask (but I strongly suggest you do) the packages you need are:

  • cider
  • clojure-mode
  • auto-complete
  • ac-nrepl

The last two are not absolutely necessary, but it’s good to have some auto complete goodness included. Once those packages are included, add this somewhere in your Emacs config:

(add-hook 'cider-mode-hook 'cider-turn-on-eldoc-mode)

That’s it. If you execute ‘cider-jack-in you’ll be dropped to a Clojure REPL. Nice. Now for auto completion. For it to truly work, that is to have auto completion both in your REPL buffer as well as your Clojure file buffers you need the cider-nrepl leiningen plugin in your Clojure project. How do you do that? There are two options:

  1. Add it to your project
  2. Add it globally to all your Clojure projects

I prefer to add it globally, since virtually all my projects are (or rather will) be coded from Emacs. For this create a ~/.lein/profiles.clj file (you are using leiningen right?) add add the following:

{:user {:plugins [[cider/cider-nrepl "0.6.0"]]}}

Telling leiningen “listen, all my projects use the cider-nrepl plugin”. Now create your project with lein new my-project and you are well on the road for Clojure auto completion.

The last step is telling Emacs to use the new auto completion source. It is done like this:

(require 'ac-nrepl)
(add-hook 'cider-repl-mode-hook 'ac-nrepl-setup)
(add-hook 'cider-mode-hook 'ac-nrepl-setup)
(eval-after-load "auto-complete"
'(add-to-list 'ac-modes 'cider-repl-mode))

Auto complete for everyone! Whenever you visit a Clojure buffer, eval it first to allow the REPL to know about your file, so it is able to provide auto completion for you. This is done with ‘cider-eval-buffer. Once the buffer is eval-ed you’ll be able to do something like this:

Emacs and Clojure

Emacs and Clojure.

Isn’t it cool?