Welcome to Clojure in Belgium ... let's start with a little Clojure that exemplifies what the venerable SICP tells us

A powerful programming language is more than just a means for instructing a computer to perform tasks. The language also serves as a framework within which we organize our ideas about processes. Thus, when we describe a language, we should pay particular attention to the means that the language provides for combining simple ideas to form more complex ideas. Every powerful language has three mechanisms for accomplishing this:

  • primitive expressions, which represent the simplest entities the language is concerned with,
  • means of combination, by which compound elements are built from simpler ones, and
  • means of abstraction, by which compound elements can be named and manipulated as units.

Primitive expressions

Note: all of the code examples are live and interactive - and can be edited by you


    (+ 1 2 3 4)

Clojure is a LISP so code is always in the form of a list within parentheses like this:

(function zero or more arguments)

In this first example, we have the function '+' and the arguments 1, 2, 3 and 4. The +, like the other maths functions, acts accumulatively. Logic can operate in the same way:


    (<= 1 2 3 4)

Means of combination

Functions are combined by nesting them in lists. They are evaluated from the inside out:


    (+ 10001 (rand 10))

In this case the rand function returns a number (from 0-9) and the + function then evaluates. This browser based evaluator (Klipse) has a magic trick where it can be put on a loop - your edits will be in the loop too :)


    (map (fn [n] (rand n)) (range 1 4))

map is an example of combining functions over a sequence. map take a function followed by a sequence, on which that function will apply to each element of the sequence in turn.

Evaluation occurs from the deepest nested list and then from right to left. Reading from right to left the range function is evaluated and produces a list of numbers from 1 to 3.

The anonymous function (fn [n] (rand n)) is invoked by map for each element and a radom number up to each value of n is produced. By default map produces a lazy sequence of all of its results. This means that when map is composed with other functions, the dependent function is fluid: it can operate on the next output element as soon as it is produced.

Means of abstraction

We already saw an anonymous function but abstraction comes from being able to name functions and call them ourselves.


    (defn greet [you] (str "Hello " you))

    (map #(greet %) (take (rand 3) ["Belgium" "Vlanderen" "Wallonie"]))

It's so simple to combine our own made functions with the standard functions without any further ceremony. You have probably worked out that #(greet %) is a shortcut to the anonymous function that we used with map earlier and % is the placeholder for the value on each iteration.

Now you're hooked - here's some more stuff!

This has been a trivial taster of the joys of Clojure but you really do now have the conceptual building blocks to make real progress!

Clojure is not an academic or toy language. It is production ready with a rich eco-system and extensive interoperability features for Java and JS

Here are a small set of curated links to quality resources that will help you along the way, whilst waiting for the next meetup!

Cognitect

Clojurian Slack

YouTube

Online learning

Training

Books

Podcasts

Community built documentation