dark mode light mode Search Menu
Search

Clojure (or Common Lisp)

The language we’ll be talking about this issue, Clojure (said as “closure”), ties together a couple of ideas we’ve introduced in prior issues.

Two issues ago we talked about Kotlin, a language that ran on the Java Virtual Machine (JVM). Languages built on top of the JVM have a couple of advantages. The first big one is that it helps the language run on any platform where Java can. That effectively means everything except iOS devices. The second one is that languages that use the JVM get access to all the library code that comes standard with Java, which is not a small amount of pre-written code you get to use.

The other idea we’ve mentioned is macros, which we briefly introduced when talking about Julia. Macros are, essentially, code-that-writes-code. A language that has macros allows you to expand the language with things like new control flow constructs, radically different syntax, or even big features like object oriented programming.

Clojure, as you might have guessed, is a language that runs on the JVM and has macros.

Clojure is a part of the Lisp family, a very old and storied family of programming language that go back to the 1950s! The Lisps include a number of languages still in use today such as Common Lisp, Scheme, Racket, Emacs Lisp, Pico Lisp, and of course Clojure. Even Julia could be considered a part of the Lisp family, though it looks fairly different.

One of the things that basically all the Lisps have in common is a very simple syntax, which makes them both easy to learn and makes it easier to write macros. This usually means Lisps have prefix syntax with lots and lots of parentheses. For example, in most Lisps adding two numbers looks like (+ 2 3) instead of 2 + 3. If you remember from the last time when we talked about Julia, there’s a cute way you can estimate pi by using random number generation.

The Clojure code for that program looks like:

(defn calcPi [n]
  (loop [timesLeft n hits 0]
    (let [x (- (rand) 0.5)
	  y (- (rand) 0.5)]
  (if (= timesLeft 0)
	(double (/ (* 4 hits) n)) 
	(if (<= (+ (* x x) (* y y)) 0.25)
	  (recur (dec timesLeft) (inc hits))
	  (recur (dec timesLeft) hits))))))
 
(println (str "pi is approximately: " (calcPi 10000000)))

Contrast this with our Python implementation from last time!

import random
numTimes = 10000000
hits = 0
 
for i in range(numTimes):
    x = random.random() - 0.5
    y = random.random() - 0.5
    if (x**2 + y**2) <= 0.25:
	hits = hits + 1
 
print('pi is approximately: ', 4 * hits/numTimes)

These don’t just look different because of all the parentheses but because they’re fundamentally very different programs. You see, Clojure is a little bit opinionated about how you write your code: it wants you to write your programs in a functional way that doesn’t default to changing the contents of variables.

In Python, you’re changing the variable “hits” over and over again to count up. Meanwhile, in our Clojure solution we’re efficiently using recursion with the loop and recur constructs. This makes our Clojure solution more like the following in Python:

import random
 
def calcPi(numTimes, n, hits=0):
    if n==0:
	return (4*hits /numTimes)
    else:
	x = random.random() - 0.5
	y = random.random() - 0.5
 
	if (x**2 + y**2) <= 0.25:
	    calcPi(numTimes, n - 1, hits + 1)
	else:
	    calcPi(numTimes, n - 1, hits)
 
def topCalcPi(numTimes):
    return calcPi(numTimes,numTimes)
 
print('pi is approximately: ', topCalcPi(1000000))

Which, if you actually try to run will cause a runtime error because Python isn’t built for these kind of efficient recursive solutions.

I think this is a decent example of how different languages push you towards different styles of solution, and if you’ve mostly used languages like Python, Java, or any of the C-family languages, then Clojure is going to gently nudge you to writing very different programs than you might be used to. If you’ve used Scheme, Racket, Haskell, ML, or any language like that before then you’ll be on pretty familiar ground with Clojure.

You can get started with Clojure by first going to the Getting Started page on the main website (https://clojure.org/guides/getting_started) and following the instructions there. If you’re on Windows instead of Mac or Linux, you’ll probably want to start with Leinengen (https://leiningen.org/) first to get set up.

Once you’ve got a working Clojure installation, I think the best way to learn the language is with the Clojure Koans. They’re available on GitHub (https://github.com/functional-koans/clojure-koans).

The “Koans” style of language tutorials started years ago with the Ruby Koans. Despite the distinctly Buddhist name, they’re just small self-contained programming puzzles where you need to fill-in-the-blanks to complete the program. They’re designed to be a progression that teaches you a programming language bit-by-bit as you figure out how to write code that uses all the different features of the language. The Clojure Koans in particular are a really nice example of this tutorial genre. If you’ve never used any kind of functional language or Lisp family language before, I really recommend starting with them.

Before we end this introduction to Clojure, I’d be remiss to not mention a very closely related language: ClojureScript. ClojureScript is almost-but-not-quite Clojure-compiling-to-JavaScript. The differences between the two are summarized on the ClojureScript site (https://clojurescript.org/about/differences), but this page will mostly make sense once you’re comfortable with Clojure.

I really like Clojure and think it’s a good example of what a modern and easily accessible Lisp can be!

Learn More

ClojureScript differences

https://clojurescript.org/about/differences

Clojure homepage

https://clojure.org/

Clojure Koans

https://github.com/functional-koans/clojure-koans

Getting started writing games in Clojure

https://lambdaisland.com/blog/08-12-2016-game-development-with-clojure-clojurescript