Uncovering Lisp

Most programming languages have several syntax rules. Lisp has one: everything is a list. The first element is a function name, and the rest are its arguments. Thus, the language is simply a collection of compile- and run-time functions, trivially extensible.

foo(1, 2, 3); const a = 1; if (a == 1) foo(); else bar(); const b = (a == 1) ? 2 : 3; (foo 1 2 3) (def a 1) (if (= a 1) (foo) (bar)) (def b (if (= a 1) 2 3))

But parentheses in Lisp are infamous for bunching together at the end of long expressions. This indentation convention can be jarring at first if you are used to curly braces in other languages being on their own lines:

(defn foo [a b] (let [ x (+ a b) ] (println "The sum is" x) ) ) (defn foo [a b] (let [x (+ a b)] (println "The sum is" x)))

The idea behind this convention is to make every line inform with content rather than just parens. Readability is helped by employing a Python-like indentation style. This achieves a sort of balance— Indentation allows you to skim while the parens allow you to inspect:

(defn foo [a b] (let [x (+ a b)] (println "The sum is" x))) (defn foo [a b] (let [x (+ a b)] (println "The sum is" x)))

Though both perspectives are visible at once, we must focus on one at a time. A LEGO analogy helps here. Imagine each list in the previous example as a LEGO block stacked over its parent. Checking the sides to see the layers below is like checking the parens at the end of a line.

This is a physical analog to the way we read Lisp code. Now let's look at the space of tooling solutions that we use for writing Lisp code and specifically how Parinfer can help.