Clojure with M-expressions

What’s wrong with Clojure or Lisp in general?

Clojure has been my go-to language for more than 15 years now. My first professional Clojure assignment was back in 2009, when Clojure was very young. I’ve used many other languages since then, and I like a lot of them, but Clojure is still where I feel most productive.

I often wish I could be just as productive in a statically typed language. The safety and guidance of a strong type system should make me faster, not slower. But so far, Clojure is where I’ve consistently found that balance of power and productivity.

Many people still complain about its syntax. That there are too many parentheses. Even non-programmers say that Clojure, being a Lisp, uses too many.

I don’t see that increase when I compare with popular languages like Java, C#, C, or JavaScript. Python code has fewer thanks to indentation, and ML-style languages, like F# usually have fewer. I grew up programming Pascal and switched to C, and then C++ when I was still a kid. Sure, C had more parentheses than Pascal, and type declarations were declared on the wrong side, which was a bit annoying.

What’s with those parentheses? Is mathematics the reason Lisp appears to look so strange?

We write 3 * (4 + 5) rather than surrounding it all, like: (3 * (4 + 5))

Is it the leading parenthesis that feels so odd?
Is a leading parenthesis a stop sign for most people?
Do most people think “Oh, a parenthesis! What did I miss?”, when it appears at the beginning of a line.
Do most of us start scanning backwards to find that missing part?

Would it be simpler if hello world in Clojure looked like:

defn hello [a]
  println (format ("Hello %s" a))

rather than its correct syntax:

(defn hello [a]
  (println (format "Hello %s" a)))

Other languages

Compare with Python, which is so popular today:

def hello(a):
    print(f"Hello {a}")

Or in Java:

void hello(String a) {
   print("Hello %s".formatted(a));
}

Or maybe TypeScript:

function hello(a: string): void {
    console.log(`Hello ${a}`); 
}

What about those trailing parentheses?

I can understand why the leading parenthesis looks odd. I can also understand why the three closing parentheses on the same line look odd:

(defn hello [a]
  (println (format "Hello %s" a)))

But those closing parentheses are just tradition. They can just as well be written one per line, to form blocks, like in C-style languages:

(defn hello [a]
  (println 
     (format "Hello %s" a)
  )
)

In Lisps, most people think it’s a waste of precious screen lines to write code in blocks. Indentation tells the same story, like in e.g. Python. The more you can see at once, the better.

There are only two kinds of languages: the ones people complain about and the ones nobody uses. There is more than one interpretation of that quote.

Lisp code is data

Clojure, and Lisp code in general, is made of data structures with a syntax called S-expressions. It’s a bit like writing code in JSON or XML, but with a more powerful format. This contributes a lot to the leverage many people feel when working with Lisps, like Clojure. It makes code simpler and easier to live with.

In principle all programming languages have a syntax that gets parsed into a data structure, an abstract syntax tree, which is then analyzed and translated into machine instructions. In Clojure, in Lisps, the code is that syntax tree from the beginning. The parentheses represent sequences of symbols, where the first element is the function being called.

M-expressions vs S-expressions

John McCarthy apparently suggested another syntax when describing Lisp: M-expressions, while S-expressions were the notation for the syntax tree that M-expressions got compiled into. But his colleagues found it easier to write expressions directly in S-expressions. As I understand it, M-expressions remained unfinished, arguably until much later.

So, should hello world have looked like this instead:

defn[hello[a],
     println[format["Hello %s", a]]]

Would Clojure have been more popular if hello world was written in M-expressions?

Apple once started on Dylan, a lisp language with algol like syntax. I guess hello world looked something like:

define function hello (a :: <string>) => ()
  format-out("Hello %s\n", a);
end function hello;

You won’t learn anything new if you want everything to be familiar.


All #ai #art #clojure #csharp #data-structures #database #datomic #emacs #fortran #fsharp #functional #gpt #haskell #history #immutability #java #jit #jmm #lambdas #lisp #pioneers #poetry #programming #programming-philosophy #randomness #rant #reducers #repl #smalltalk #sql #threads #unix #women