Learning Clojure/Coding Conventions

From Wikibooks, open books for an open world
Jump to navigation Jump to search

Because Clojure code is just a bunch of literals, it is hard to read if not indented in a readable style. Well-formatted Clojure looks like this:

(defn my-zipmap [keys vals]
  (loop [map {}
         ks (seq keys)
         vs (seq vals)]
    (if (and (not-empty ks) (not-empty vs))
        (recur (assoc map (first ks) (first vs))
               (rest ks)
               (rest vs))
(my-zipmap [:a :b :c] [1 2 3])

The general idea here is that, when spread onto multiple lines, the elements of a list or vector should be indented on the lines below. Notice that the line beginning (loop is indented in by two spaces under (defn because the list starting (loop is a direct element of the list starting (defn. However, below that, the author broke from this rule by choosing to line (recur with (and above instead of two spaces in from (if. Also note that the vector starting [map starts interior to its line, so the two lines below continuing the vector are aligned just right of the opening [. The rules are:

  1. Indent continuation lines by 2 spaces...
  2. Unless there is an opportunity to align opening (, [, or { characters...
  3. Or unless continuing an interior literal.

In essence, always indent in underneath the (, [, or { to which an element belongs. Admittedly, this scheme does take some getting used to, both to read and to write.

It's quite typical in Lisp that you end up with many trailing parentheses:

(defn supply-arg [arg flist]
  (loop [flist flist cnter 0]
     (if (first flist) (do ((first flist) arg) 
                           (recur (rest flist) (+ 1 cnter))))))   ; remember, the + in this line is just an ordinary symbol

Text editors like Emacs can help you cope with parentheses matching and indentation style.

« Learning Clojure
Coding Conventions
Basic Syntax Functional Programming