Posts Tagged ‘clojure’

Programming Clojure

Saturday, October 31st, 2009

I read Programming Clojure a few months ago; I meant to write a review of it then, but I was busy and then forgot. Better late than never, though, so I’m going to do it now. Clojure, as you may know, is a Lisp dialect that runs on the JVM. It is a very modern Lisp - Clojure 1.0 celebrated it’s first anniversary recently. It can integrate with Java libraries, nullifying the complaints that Lisp doesn’t have enough libraries, and has very good concurrency support.

Programming Clojure was a very good book for helping to get started with Clojure. I had already done a few small projects with it, but hadn’t used it in any substantial way. This book covered all of the features of Clojure, including all of the neat concurrency stuff that I probably wouldn’t have run into on my own for a while. This book provides a good overview of all the features of Clojure, as well as simple examples of how to use them. I still refer to it when writing Clojure code.

In addition to talking about the language features in isolation, there is an overarching project throughout the book that is used to show the features in a real application. This is pretty interesting, even though you’d probably never have to write a build system in real life. This project starts simpler, and then gradually uses more of the concepts you learn in each chapter, making it a great way to follow along and ensure you actually understood what you read in the book. It’s fairly short; I recommend everyone who reads the book should make sure they understand the project.

I’d highly recommend this book if you are interested in learning or getting better at Clojure. It will help you understand how to use Clojure to create real projects. It explains how to use clojure, some of the issues you may initially have with them (printing in lazy sequences, for example), and how to overcome them.



Initial Thoughts on Clojure

Monday, July 20th, 2009

So if you’ve been following my blog, you know that I’ve been playing around with Clojure. I’ve written enough of it to feel comfortable writing my initial thoughts on it, so here they are.

The Good
Clojure has good interoperability with Java, so calling most Java libraries is quite easy. This is it’s main selling point, of course: many people have issues with Lisp not having standard libraries and so not being portable across implementations, but Clojure comes with a full set of libraries built-in. The java interop is natural, with you being able to either call java methods on objects with the class you are operating on at the start of the argument list:

(. 3 toString)

Or at the start:

(.toString 3)

The first is used more widely, especially with the .. macro that allows you to chain calls on functions:

(.. 3 toString getBytes)

Is equivalent to

(.getBytes (.toString 3))

Clojure also uses few parentheses than other lisps: forms which don’t really need parenthesis around them, such as let or cond, have had their extraneous parens removed. Instead of

(cond ((> num 0) 1)
        ((< num 0) -1)
        ((= num 0) 0))

In clojure, you have:

(cond (> num 0) 1
       (< num 0) 0
       (= num 0) 0)

which I find easier to scan. Clojure’s use of vectors and [] to specify bindings also helps reading the code, allowing you to more quickly see where the bindings begin and end. These additions just make the language easier to read.

The way to specify multiple argument lists for Clojure functions is clear, although a bit verbose. I like the python method of being able to specify default arguments in the argument list directly, but Clojure’s is pretty good as well. The way it works is that defn has a form where you can specify what hapens for each argument list, e.g.

     (defn make-rectangle
       ([width height] {:width width :height height})
       ([width] (make-rectangle width width)))

This function will accept either 1 or 2 arguments, defaulting to the second argument being the value of the first if it is not provided. This pattern follows the Java/C# pattern of implementing method overloading, where the methods with fewer arguments call the primary overloaded method.

Clojure makes creating simple anonymous functions easy with the #( reader macro. It’s simple: #( will start an anonymous function where the arguments are reference by %n, where ‘n’ is the nth argument. % alone stands for the first argument. For example:

(defn make-eql [num]
      #(= num %))

Just returns an anonymous function that will compare its argument to num. While for more complicated anonymous functions you will need to use the fn special form, in most cases I find that anonymous functions do not need to be very complex.

Clojure has only one namespace for functions and variables, like Scheme and unlike Common Lisp. This is the main reason I prefer working in Scheme to CL, so the fact that Clojure decided to use only one namespace is amazing. Not having to funcall every variable that has a function stored in it makes me happy.

Clojure has syntax for a few data structures, namely lists(of course), vectors, maps, and sets. These are implemented as functions, which saves a great deal of effort. Instead of having to do something like

(elt [1 2 3] 1)

to get the element at index 1, in Clojure you would just do

([1 2 3] 1)

Similarly for maps: To define and use these, you can just do

(def my-map {:foo 1 :bar 2})
(my-map :bar)

Since I had to use maps extensively while working in Clojure so far, this easy syntax for them is very nice. This is actually true of pretty much all languages - hashmaps are one of the most useful data types.

The Bad
There is, unfortunately, a fair amount of things that make Clojure a pain to work in. Most egregious of these are the error messages you get when something fails - which is precisely when you need the most information. For example, here’s one error message I got while developing the AVL tree in it’s entirety:

java.lang.IllegalArgumentException: Don't know how to create ISeq from: Integer
No Line Number

No message.
  [Thrown class java.lang.ClassCastException]

Restarts:
 0: [ABORT] Return to SLIME's top level.

Backtrace:
[No backtrace]

I never actually managed to figure out why this was occurring, instead rewriting the offending section in a different way. While a lot of the errors gave more information than this one(which isn’t hard), many of them didn’t provide any *useful* information, such as the following backtrace:

  0: clojure.lang.LazySeq.sval(LazySeq.java:47)
  1: clojure.lang.LazySeq.seq(LazySeq.java:56)
  2: clojure.lang.RT.seq(RT.java:439)
  3: clojure.core$seq__3750.invoke(core.clj:103)
  4: clojure.core$print_sequential__5992.invoke(core_print.clj:42)
  5: clojure.core$fn__6077.invoke(core_print.clj:136)
  6: clojure.lang.MultiFn.invoke(MultiFn.java:161)
  7: clojure.core$pr_on__4779.invoke(core.clj:2019)
  8: clojure.core$pr__4782.invoke(core.clj:2029)
  9: clojure.lang.AFn.applyToHelper(AFn.java:173)
 10: clojure.lang.RestFn.applyTo(RestFn.java:137)
 11: clojure.core$apply__3860.doInvoke(core.clj:390)
 12: clojure.lang.RestFn.invoke(RestFn.java:428)
 13: clojure.core$pr_str__5146.doInvoke(core.clj:2761)
 14: clojure.lang.RestFn.invoke(RestFn.java:413)
 15: swank.core$send_repl_results_to_emacs__450.invoke(core.clj:54)
 16: swank.commands.basic$eval__969$listener_eval__971.invoke(basic.clj:55)
 17: clojure.lang.Var.invoke(Var.java:346)
 18: user$eval__10400.invoke(NO_SOURCE_FILE)
 19: clojure.lang.Compiler.eval(Compiler.java:4601)
 20: clojure.core$eval__4610.invoke(core.clj:1730)
 21: swank.core$eval_in_emacs_package__453.invoke(core.clj:58)
 22: swank.core$eval_for_emacs__530.invoke(core.clj:126)
 23: clojure.lang.Var.invoke(Var.java:354)
 24: clojure.lang.AFn.applyToHelper(AFn.java:179)
 25: clojure.lang.Var.applyTo(Var.java:463)
 26: clojure.core$apply__3860.doInvoke(core.clj:390)
 27: clojure.lang.RestFn.invoke(RestFn.java:428)
 28: swank.core$eval_from_control__456.invoke(core.clj:65)
 29: swank.core$eval_loop__459.invoke(core.clj:70)
 30: swank.core$spawn_repl_thread__591$fn__622$fn__624.invoke(core.clj:179)
 31: clojure.lang.AFn.applyToHelper(AFn.java:171)
 32: clojure.lang.AFn.applyTo(AFn.java:164)
 33: clojure.core$apply__3860.doInvoke(core.clj:390)
 34: clojure.lang.RestFn.invoke(RestFn.java:428)
 35: swank.core$spawn_repl_thread__591$fn__622.doInvoke(core.clj:176)
 36: clojure.lang.RestFn.invoke(RestFn.java:402)
 37: clojure.lang.AFn.run(AFn.java:37)
 38: java.lang.Thread.run(Thread.java:619)

(OK, I promise not to include any more full stack traces). I got this stack trace while testing tree insertion. Do you notice anything funny about the stack trace? It’s pretty easy to miss if you aren’t looking for it, so don’t feel bad if you don’t. This actually has no references to code that I wrote. The entire thing is refers to clojure, java, and swank functions, none of which I care about, instead of the stack trace for the code *I* wrote, which I did. I did manage to find out where this was happening: Apparently, if an error is thrown in the body of a ‘for’ loop, the trace information from the body of the for is lost. To try this yourself, evaluate the following:

(defn foo []
  (throw (java.lang.Exception.)))
(for [x '(1)]
     (foo))

And see the lack of a call to foo in your stack trace.

This is a consistent problem across Clojure’s errors: many errors from it don’t provide even a line number when called from SLIME. This isn’t even just a few of them, either; it looks like every error that deals with syntax doesn’t tell you the line number of where the error occurred This happens when you use () for binding instead of [], when you have an extraneous paren somewhere in your code(these can be pretty annoying to find without a line number), when your if has too many arguments, etc. While trying these on clojure.lang.repl *does* give information about line numbers, This information doesn’t appear to be part of the exception and so isn’t shown when you error from something you can actually use.

This issue is the main problem I have with clojure. The lack of usable information on errors can just make it a pain to work with, even though I like the language itself. I’m not sure how the REPL displays line numbers, and my SLIME *is* connecting to the same jar file I used to get line numbers for syntax errors, so apparently there is something built-in that can’t be taken advantage of by external editors, which is very unfortunate. Even the errors which do have line numbers and stack traces make the information difficult to find by burying it with all of the calls to ‘eval’ and such that clojure uses behind the scenes.

A more minor issue is that Clojure lacks forward declaration, so you have to (declare) everything up at the top if you want to be able to rearrange code however you want. This isn’t a huge deal, but it can get pretty annoying.

The lack of implied tail-call optimization bugs me, but it’s something I can live with. It isn’t too difficult to remember to use recur or trampoline, and I can understand why it might be better to have to programmer specify all the time they want to do TCO, instead of having the compiler figure it out for a subset of these calls. I would like the JVM to introduce a whatever new bytecode is necessary so that implied TCO is possible in all cases, though. This didn’t come up in my projects, but it could have if I had tested on a tree with, oh, 2^1024 or so nodes.

I would also like Clojure to have programmable reader macros, even though it wouldn’t have helped much on this project. The clojure designers realize that reader macros can be very useful - they have a few built-in to the reader, such as for sets, anonymous functions, and regexs - but do not allow regular programmers the luxury of defining their own. I understand why, and for the most part it’s a philosophical difference, so this isn’t that big of a deal to me.

Overall, I do like Clojure, despite it’s terrible error messages. It also looks like the Clojure guys are aware this is an issue and trying to fix it, as well, so hopefully this will be a lot better soon. I’m definitely going to keep using Clojure at least a bit, though I’m not sure whether I’ll make it one of my primary programming languages yet.

AVL Tree Implementation in Clojure

Friday, July 17th, 2009

To learn Clojure (and data structures) better, I decided to write an AVL tree implementation in Clojure. It was complicated enough that I ran into problems with Clojure, while still being doable in about a day, so it was about the right size for what I wanted to do.

An AVL tree is a balanced binary search tree, optimized for fast lookups. It’s much like a Red-Black tree, except it has faster asymptotic lookup times. At any node, the difference between the height of the node’s subtrees can be at most 1 - if this invariant is not true, the tree is not a valid AVL tree. The implementation I wrote is entirely immutable: It doesn’t ever change the data on a node, just creates a new one. This is great for concurrency, since there aren’t ever any locking issues on immutable data.

(import '(java.util Random))
(use 'clojure.contrib.test-is)

These are just the imports needed to implement the AVL Tree. The only Java library you need if for generating random numbers, and Clojure’s test-is framework was what I used for unit-testing some of the smaller methods.

(defstruct avl-tree :data :height :left :right)

Defining an avl-tree structure. Ended up only using it it one place and just overwriting attributes with assoc usually, but this also serves as documentation of the structure.

(defn get-height
  "Returns the height of an AVL tree, or -1 if nil"
  ([tree] (if tree (tree :height) -1))
  {:test (fn []
	   (is (= (get-height {:height 0}) 0))
	   (is (= (get-height nil) -1)))})

This gets the height of an AVL tree, or just -1 if the tree doesn’t exist. This is very useful, since it allows treating empty-subtrees the same as actual nodes for purposes of height calculations. If we just attempted to do (tree :height), a null pointer exception could be thrown, instead of returning -1.

(defn balance-factor
  "Returns the height of the right subtree - height of left subtree"
  ([tree] (- (get-height (tree :right)) (get-height (tree :left))))
  {:test (fn []
	   (is (balance-factor {:right {:height 3} :left {:height 5}}) -2))})

This just returns the balance factor, which the height of the right subtree minus the height of the left subtree. This is less than 2 for all nodes in a AVL tree.

(defn rrotate [tree]
  "Performs a right rotation on an AVL tree"
  (let [right-height (inc (max (get-height (tree :right))
       		     	       (get-height ((tree :left) :right))))]
    (assoc (tree :left)
      :height (inc (max right-height (get-height ((tree :left) :left))))
      :right (assoc tree
	       :height right-height
	       :left (if (tree :left) ((tree :left) :right) nil)))))
 
(defn lrotate [tree]
  "Performs a left rotation on an AVL tree"
  (let [left-height (inc (max (get-height (tree :left))
       		    	      (get-height ((tree :right) :left))))]
    (assoc (tree :right)
      :height (inc (max left-height (get-height ((tree :right) :right))))
      :left (assoc tree
	      :height left-height
	      :right (if (tree :right) ((tree :right) :left) nil)))))

These methods perform left and right rotations on AVL trees - they also work for any type of binary tree, but for those they will append extra information(probably incorrect) about the height. Tree rotations are used in AVL and Red-Black trees to maintain the invariants. They are operations that can be performed that rearrange the nodes in a binary search tree in a way that the tree is still valid, essentially by ‘rotating’ about a pivot node. For more information about these, look here.

(defn balance [tree]
  "Return a balanced version of the AVL tree"
  (if tree
    (if (< (Math/abs (balance-factor tree)) 2)
      tree
      (cond
	(= (balance-factor tree) 2) (if (>= (balance-factor (tree :right)) 1)
				      (lrotate tree)
				      (lrotate (assoc tree :right (rrotate (tree :right)))))
	(= (balance-factor tree) -2) (if (<= (balance-factor (tree :left)) -1)
				       (rrotate tree)
				       (rrotate (assoc tree :left (lrotate (tree :left)))))))))

This method balances an unbalanced tree, which can arise after insertion or deletion of a node from an AVL tree. Since the tree was balanced before the node was inserted or removed, the maximum difference in subtree heights is 2, and if the balance factor for a node is either 2 or -2 you must rebalance the tree by performing rotations based on the balance factor of the subtrees. If the balance factor of the current node is 1, 0, or -1, the node is a valid AVL tree and does not need to be rebalanced. However, nodes closer up the root may be invalid AVL trees and so need to be rebalanced.

(defn predecessor [tree]
  (#(if % (if (% :right) (recur (% :right)) %)) (tree :left)))

This finds the predecessor of a tree, or the largest node smaller than the current node. This makes use of the # reader macro, which creates an anonymous function, and %, which stands as the first argument to the function in one of these anonymous functions. It also uses the recur form, used to specify that this recursive call should be tail-call optimized. The recur is mainly used in this context to recursively call the anonymous function; the tree would have to be very large for this to throw a StackOverflowException.

(defn tree-lookup
  "Returns the data from the tree corresponding to val if it exists, otherwise nil"
  ([tree val < >]
     (if tree
       (cond
	 (< (tree :data) val) (tree-lookup (tree :right) val < >)
	 (> (tree :data) val) (tree-lookup (tree :left) val < >)
	 true (tree :data))
       nil))
  ([tree val] (tree-lookup tree val < >)))

This is the standard binary search tree lookup function, generalized so that custom comparators can be passed in. It works on any type of BST, assuming they are implemented as maps with a :left and :right field. I also like how clojure and other lisps allows you to define operators such as < and >, making for much cleaner-looking code. This function has multiple different ways to call it: you can call with the specifying all of [tree val < >], where tree is the tree to look in and val is the value to look for, or just [tree val], where < and > will default to numeric < and >.

(defn avl-insert
  "Inserts a new node into an AVL tree"
  ([tree val < >]
     (if tree
       (balance
	(cond
	  (> (tree :data) val)
	  (let [left (avl-insert (tree :left) val < >)]
	    (assoc tree
	      :height (inc (max (get-height left) (get-height (tree :right))))
	      :left left))
	  (< (tree :data) val)
	  (let [right (avl-insert (tree :right) val < >)]
	    (assoc tree
	      :height (inc (max (get-height (tree :left)) (get-height right)))
	      :right right))
	  true (assoc tree :data val)))
       (struct avl-tree val 0)))
  ([tree val] (avl-insert tree val < >)))

This is the function for inserting a node into an AVL tree. It also allows you to specify comparators - I’d like to be able to specify them on the AVL tree itself somehow so there was less chance of mistakes by passing in different < and > functions, but I couldn’t figure out a way to do it without having to have the comparators specified whenever you created a new node anyway, which still leaves the problem. If the tree you pass in is nil, it just creates a new avl-tree with that value and returns it; otherwise, it does a standard BST insert and calls balance on each subtree it visited. While balance doesn’t need to be called on every one, the calls to balance that are unnecessary will do no work anyway and so probably aren’t much of a performance hit.

 (defn avl-remove
   "Removes a node from an AVL tree"
   ([tree val < >]
      (if tree
	(balance
	 (cond
	   (< (tree :data) val) (let [right (avl-remove (tree :right) val)]
				  (assoc tree
				    :right right
				    :height (inc (max (get-height (tree :left))
						      (get-height right)))))
	   (> (tree :data) val) (let [left (avl-remove (tree :left) val)]
				  (assoc tree
				    :left left
				    :height (inc (max (get-height (tree :right))
						      (get-height left)))))
	   true (if (not (= (tree :height) 0))
		  (let [new-tree
			(if (predecessor tree)
			  (let [left (avl-remove (tree :left) ((predecessor tree) :data))]
			    (assoc tree
			      :data ((predecessor tree) :data)
			      :height (inc (max (get-height (tree :right))
						(get-height left)))
			      :left left))
			  (tree :right))]
		    (assoc new-tree
		      :height (inc (max (get-height (new-tree :left))
					(get-height (new-tree :right)))))))))))
   ([tree val] (avl-remove tree val < >)))

This is the function to call to remove a node from an AVL tree, and it is the most complicated function is the set. To remove it, you descend down the subtree until you find the node you wish to remove. If it is a leaf node, you can just remove it. If the left subtree is nil, the node is just replaced with the right subtree of the node. Otherwise, the node is given the data of it’s predecessor and then the predecessor is removed from the left subtree. This is all done immutably, of course. Once this new node is created, the tree is balanced at each node leading up from where the node was finally removed from to the root node, ending with a balanced AVL tree.

(defn assert-correct-heights [tree]
  (if tree
    (do
      (assert (< (balance-factor tree) 2))
      (assert (.equals (tree :height) (inc (max
					    (assert-correct-heights (tree :left))
					    (assert-correct-heights (tree :right))))))
      (tree :height))
    -1))

This is a function I used to test an AVL tree. It will go through the tree, make sure that all the heights are correct and that the tree is balanced at every node. If this is the case, then the tree is a valid AVL tree and it returns the height. If it is not, an exception is thrown.

(defn test-all []
  (dotimes [x 100]
    (def tree (ref (avl-insert nil 50)))
    (let [rand (Random.)]
      (dotimes [x 100]
	(dosync
	 (alter tree avl-insert (.nextInt rand 1000))))
      (assert-correct-heights tree)
      (def tree (deref tree))
      (dotimes [x 1000]
	(let [t (avl-remove tree x)]
	  (assert-correct-heights t)
	  (assert (not (tree-lookup t x)))))
      (def tree (ref tree))
      (dotimes [x 1000]
	(dosync
	 (alter tree avl-remove x)
	 (assert (not (tree-lookup (deref tree) x)))
	 (assert-correct-heights (deref tree))
	 )))))

This test puts the AVL tree through it’s paces. It creates a reference to an AVL tree so I could conveniently insert items into it. The tree is initially an already-inserted AVL tree because, unfortunately, (ref nil) is not to nil and so was giving null pointer exceptions on the first insert. The tree then has 100 random elements inserted into it, using dosync and alter to mutate tree. Once these insertions are done, this tree is checked to ensure it is a valid AVL tree. The tree then has each of it’s elements removed from it non mutably (so each node is removed once, but this does not effect the next removal which removes from the entire tree), which in a tree of this size will probably test each possible removal scenario. Each time a node is removed, the tree is checked for validity. After this, each node is removed and the tree is mutated one at a time randomly, leaving a nil tree at the end. At each intermediate step, the tree is checked for validity. This entire process is repeated 100 times. This test can take a while to finish, but once it’s done you can be pretty sure the tree works.

Booklist Generation in Clojure

Tuesday, July 14th, 2009

I recently decided to learn Clojure, a Lisp that runs on the JVM. Since it does, it can take advantage of all of Java’s libraries. I’ve programmed in both Common Lisp and Scheme before, and so it wasn’t very difficult to pick up, but it may be harder for someone who hasn’t used a Lisp before.

The best way to learn a language is to use it, so I decided to create it to generate the booklist that is now on my sidebar. This was a very simple task, so it only took me about an hour or so while learning Clojure. The code and my explanations of it and some issues I ran into follow: If you know any ways to improve it, please let me know.

 (def book-list
  {:categories
   [
    {:name "Nonfiction - Technical"
     :books [
	     {:title "Hacker's Delight"					:asin "0201914654"}
	     {:title "The Craft of Text Editing"			:asin "0387976167" :blog "http://nflath.com/2009/04/the-craft-of-text-editing"}
	     {:title "On Lisp"						:asin "0130305529"}
	     {:title "Practical Common Lisp"				:asin "1590592395"}
	     {:title "Java Puzzlers"					:asin "032133678X"}
	     {:title "The Little Schemer"				:asin "0262560992"}
	     {:title "The Reasoned Schemer"				:asin "0262562146"}
	     {:title "Beautiful Security"				:asin "0596527489"}
	     {:title "Beautiful Architecture"				:asin "059651798X"}
	     {:title "A Little Java, A Few Patterns"			:asin "0262561158"}
	     {:title "The Algorithm Design Manual"			:asin "1848000693"}
	     {:title "Programming Language Concepts and Paradigms"	:asin "0137288662"}
	     ]}
 
    {:name "Nonfiction" :books nil
     }
 
    {:name "Fiction"
     :books [
	     {:title "Sensei"						:asin "0451411323"}
	     {:title "Angels and Demons"				:asin "1416580824"}
	     {:title "Belgarath the Sorcerer"				:asin "0345403959"}
	     ]}
    ]})

This data structure represents the booklist. It is a nested set that contains all the information about the organizational structure of the books. Clojure (or any lisp) allows you so record your data in ways that are both human-readable and trivially computer-readable. All operations to generate the HTML for the booklist page operate on this data structure.

(defmacro str-concat [& body]
  "Concatenates a list of sequences as a string"
  `(apply str (concat ~@body)))

Unfortunately, the concat method will not work very well on strings. Since concat works on sequences, one of which are strings, if you just concat a list of strings the result will be a sequence of characters, so you have to wrap it in an (apply str …) to get the value as an actual string. I created this as a macro instead of a function because the laziness of Clojure sequences was giving me problems when printing the final result out.

(def intro-string "These are a few of the books I've read - It is incomplete, but I'll try to keep it up to date and blog about any additional technical books I finish reading.<br>")
(def header-link-format-string "<a href="#%s">%s</a><br>n")
(def header-format-string "<h2><a name="%s">%s</a></h2>" )
(def book-link-format-string "<a href="http://www.amazon.com/gp/product/%s?ie=UTF8&tag=randmusiofaso-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=%s">%s</a><img src="http://www.assoc-amazon.com/e/ir?t=randmusiofaso-20&l=as2&o=1&a=%s" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />")
(def blog-link-format-string "<t><t><a href="%s">Blog</a><br>n")

These are just a few configuration variables that determine how the list is laid out. They ensure that links are to the correct anchor and that books are linked to Amazon and any blog posts properly, without me having to manually add the link in for each book.

(defn generate-header [book-list]
  "Generates the header of the book-list"
  (str-concat
   (for [category (book-list :categories)]
     (format header-link-format-string (category :name) (category :name)))))

This just loops over the categories in the booklist and creates a HTML link to what will be the main entry. The for macro returns a list of strings, so we have to str-concat them to get our final string. Unfortunately, format can’t refer to one argument multiple times(not that I saw, anyway - if anyone knows how to do this please tell me!), so I have to pass in the category name twice.

(defn generate-body [book-list]
  "Generates the body of the book-list"
  (str-concat
   (for [category (book-list :categories)]
     (str-concat
      (format header-format-string (category :name) (category :name))
      "<table>"
      (str-concat
	(for [book (category :books)]
	  (str-concat
	    "<tr><td>"
	    (format book-link-format-string (book :asin) (book :asin) (book :title) (book :asin))
	    "</td><td>"
	    (if (book :blog) (format blog-link-format-string (book :blog)) "<br>")
	    "</td></tr>n"
	    )))
      "</table>n"
      ))))

This is similar to the previous function, but more complicated. It generates the headings for each section, then loops through each book in each category and outputs the formatting required to link them to amazon and any blog posts I’ve made. The lazy sequences were very annoying here, forcing me to make four nested str-concats in order to get the output I needed when printed instead of just referring to lazy sequences.

(defn print-html []
  "Prints the HTML for the book-list page"
  (println intro-string)
  (println (str-concat (generate-header book-list) (generate-body book-list))))

This function essentially just prints the introduction, the header, and the body of the list. Nothing complicated is happening here.

(print-html)

This just calls the previously-defined function, giving me the HTML I need to paste into WordPress to generate a new page.

I’m working on another Clojure projects, so I’ll post more of my thoughts about the language once I finish it.

Clojure Setup for Emacs

Thursday, July 9th, 2009

I’ve recently started learning Clojure, and so of course the first thing I did was set up emacs to properly be able to format and code in it. To do this, you should first download clojure-mode. Now, manually load the file, with M-x load-file, and then perform M-x clojure-install. This only needs to be done once. The clojure-install function will install all of the necessary dependencies, including slime integration for clojure. Once this is set, I have the following to configure clojure-mode:

(require 'clojure-mode)
(add-to-list 'auto-mode-alist '("\\.clj$" . clojure-mode))
(setq clojure-src-root "/home/nflath/.emacs.d")
(setq swank-clojure-extra-classpaths '())
(clojure-slime-config)

This is admittedly a fairly minimal install. It requires clojure-mode to be installed and then sets clojure-mode to be used on all .clj files. You also have to specify the directory you specified with clojure-install as clojure-src-root. If you have any extra jar files or anything that you want Slime to know about, you need to add them to swank-clojure-extra-classpaths, and then clojure-slime-config will enable slime. Once this is done, M-x slime will load up Slime using clojure, acting as a Clojure repl. You can also send expressions in your .clj files to the repl to be evaluated with C-x C-e and all the usual emacs-lisp evaluation functions.

One note: learning the S-exp movement commands will help tremendously for editing clojure. I have only recently been using them, and they have sped up moving around the expressions by a huge amount. C-M-f is forward-sexp, which will take you to the next s-exp inside the current one, and C-M-b is backwards-sexp, which will do the opposite.