OrgPad logo

Interactive Clojure tutorial

Created by Pavel KlavĂ­k

An interactive tutorial to Clojure. Code snippet are running Klipse and it is possible to change them. The results are immediately updated.

#Clojure, #interactive, #tutorial

Interactive Clojure tutorial

Data Oriented Programming

There is an entire book which explain benefits of representing data with maps and vectors, instead of objects from OOP. This reduces the complexity, makes the system more understandable and easier to change.

Sharvit-DOP-HI

Why keywords?

Keywords serve a different purpose, they identify themselves. They can be built programatically and are very fast. They are more similar to enums in languages like C++, but they are application wide, can be serialized, etc.

To avoid collisions, it is useful to distinguish different usages with namespace prefixes. This allows easy code refactoring and searching where each keyword is used. For example, in OrgPad, we have 15 different colors for nodes/links, each represented by a keyword :color/red, etc.

Basic data types

Clojure has well-known data types to represent numbers, strings, etc. When used, they evaluate to themselves.

Interactive code snippets are powered by Klipse

Also written in ClojureScript.

https://github.com/viebel/klipse

https://blog.klipse.tech/clojure/2016/03/27/klipse-manual.html

I want to thank Yehonathan Sharvit (@viebel) for helping setting this up and improvements of several examples.

Representing data objects using maps

Map

A map consists of key-value pairs where to each key has some value assigned. Lookup and adding/removing pair takes constant time.

Data structures

Basic value can be combined into data structures. They have the following properties:

image

OrgPad itself is written in Clojure(Script)

Here, you can take a look at overview of used technologies. The ClojureScript front-end runs in React with Reagent and Re-frame. The Clojure backend is written using Ring and Aleph.

Set

An unordered collection of values, containing each value exactly once. Lookup and adding/removing values takes constant time.

Vector

An ordered collection of values. Lookup at an arbitrary index and adding/removing values from the end takes constant time.

Atoms

Not everything can be immutable, otherwise the program could never change. Atoms can be used to capture state which changes over time.

Debug macro example

1024px-Clojure logo.svg

Sequence abstraction

All Clojure data structures and many other data types implement ISeq interface. A sequence is lazy, has the first element and the rest of the elements. Most Clojure functions work on sequences. See documentation for more information.

Code is data

This property is called homoiconicity. Consider the following line:

(count [1 2 3 4 5])

As code, it is calling the count function on a vector [1 2 3 4 5]. But as data, it is a two element list containing the symbol count and the five element vector [1 2 3 4 5].

Macros

Most code transforms data from one shape into another. For example, each node of this website is described by a Clojure map. These maps are transformed into HTML data which is displayed on the screen.

Since code is just data, it is quite easy to write macros which take this data and transform it into another data, changing the code. Talking about macros is outside of scope of this tutorial, but for users I recommend this book:

cjclojure hu6d5b8b63a4954cb696e89b39f929331b 1093730 250x0 resize q75 box

Why Clojure?

Thread-last

In the thread-last macro ->, the input is inserted as the last argument. This is useful when a collection is transformed.

List

Linked lists for which it is efficient to add/remove values from the beginning. They are usually used to represent code and within macros.

Fizzbuzz sequence solution

Filter and remove

Filter is given a function and a collection. Computes a sequence of those elements for which the function returns truthy value. Remove complements filter by keeping only the remaining elements.

Java/JS interop

Clojure is hosted on JVM and ClojureScript on JavaScript. It is use any library or use any native code. Guides for Clojure interop and ClojureScript interop. Click here to open the code in another tab.

Map

Map takes a function and one or more collections. Computes a new sequence of results of applying the function on each element of the input collection(s).

Threading macros

Allows to build pipeline where some input data are processed by a series of transformations. These transformations are written from the first one till the last one.

Specialized thread macros

Higher-order functions

Higher-order functions take other functions as arguments and apply them to collections. These transformations are nowadays in every programming language, and they are incredibly clean in Clojure.

image

Try on your own

Reduce

Reduce is given a binary function, an initial value serving as an accumulator and a collection. It takes elements of the collection one-by-one. Applies the function for the current value of the accumulator and the processed element. The result is stored into the accumulator. The final value of the accumulator is returned.

Comparison and logic operators

In Clojure, a value is truthy when it is not nil and false. So 0, [], ... are truthy.

How to call a function

Instead of the usual f(x,y,z), we just write (f x y z). Commas are just whitespace in Clojure, so they are optional.

Awesome language features

Thread-first

In the thread-first macro ->, the input is inserted as the first argument. This is useful when a single object is transformed: a map, a string, a single Java/JS object.

Fizzbuzz

For number 1 to 100, output the following:

Conditions and branching

Defining symbols and functions

image

HTML templating using Hiccup

HTML is represented in Clojure using data structures in Hiccup format and it can be easily converted to HTML string using libraries. Reagent uses hiccup syntax to define React components. Hiccup is great since it is just a data structure which can easily be constructed, modified, transformed, etc.

Fizzbuzz cond solution

Basic functions for numbers

Destructuring

Destructuring allows to quickly capture values from sequences and maps. It can be used in many places: at function arguments, in let statements, within for, doseq, etc.

Simple React app with Reagent and Re-frame

Reagent is a ClojureScript wrapper for React using hiccup notation. Re-frame is a framework describing how to structure a Reagent app into four distinct parts: DB in a single atom, subscriptions which compute/read parts of DB, views which are rendered components, and events which modify DB and/or outside world. Both of these are awesome and OrgPad is build on this technology. See an interactive example.

distinct meaning

A for cycle in languages such as C can have many different meaning. Distinct functions are used in Clojure, so the meaning is immediately clear.

for - individual values of a sequence are transformed independently, the computation could be paralelized.

for (int i = 0; i < 10; i++) {   
A[i] = 2 * A[i];
}
(for [x arr]
(* 2 x))

reduce - the values are cummulated, the cycle runs are not independent.

int sum = 0;
for (int i = 0; i < 10; i++) {
sum += A[i];
}
(reduce + arr)

Anonymous functions

Local bindings with let

Let allows to define local bindings which are used in subsequent computations. It can save computation time when used repeatedly and make the code more readable.

For

Given a collection, for computes a sequence of results of applying the given form on each element. It is much more powerful than for in languages like C. Multiple collections can be used, it allows for filtering, local bindings, etc.