OrgPad logo

Programming language Clojure

Created by Pavel Klavík

#Clojure, #computer science

Programming language Clojure

JavaScript

ClojureScript is the language version which compiles to JavaScript. It uses Google Closure Compiler which optimizes and produces minimal code.

cljs-logo-120b

CLR

The original Clojure implementation adressed both JVM and CLR (.NET). Today JVM is most used but CLR should be still functional. (I personally have never used it.)

JVM

The original most used version of Clojure runs on JVM. It integrates well with existing Java libraries and on the other hand can be used to create new libraries used directly from Java. It is enought to add clojure.jar into the project.

Python and others

There exist Clojure versions for other platforms.

A hosted language on multiple platforms

The language is hosted on other platforms and we have a direct access to the environment. Therefore, it is straightforward to use an arbitrary library from the environment and on the other hand the native code can use a code written in Clojure. It is easy to add Clojure into an existing project. In many companies, it was sneaked in by some programmer and was later adapted by entire teams.

Too many parenthesis

function performMagic(value, list) {
return list.concat(value)
.map(v => v + 1)
.filter(v => v % 2 === 0)
.reduce((accumulator, v) => v + accumulator);
}
(defn perform-magic [value list]
(->> list
(cons value)
(map inc)
(filter odd?)
(reduce +)))

Based on LISP

Instead f(x,y,z) write (f x y z).

Non-problems

Absence of static type checking

Clojure has dynamic types based on the environment. There are many myths surrounding static typing:

Static types are mostly addressing typos (i.e., swapping function arguments). They do not reveal serious problems. The cost is lesser generality and a lot of additional code.

One can use automatic tests, REPL and spec in Clojure.

Used by hundreds of large companies

Used by companies such as Apple, Facebook, Netflix, WalmartLabs, ...

Screenshot (151)

Hot code reloading

An illustration on changes in the code of the game Flappy Bird. The state of the app is preserved throughout the code changes. This completely changes the way you program.

Java(Script) interop

Consider the following Java code:

JFrame f = new JFrame();
JLabel l = new JLabel("Hello World");
l.setHorizontalAlignment(SwingConstants.CENTER);
f.add(l);
f.pack();
f.show();

It can be written in Clojure in a more clear form:

(doto (JFrame.)
(.add (doto (JLabel. "Hello World")
(.setHorizontalAlignment SwingConstants/CENTER)))
.pack .show)

More informations about Java interop and Javascript interop; npm packages can be used via Shadow-cljs.

Immutable database Datomic

datomic-logo-290x230

Created by Rich Hickey in 2013.

A flipped database:

Clojure

Released by Rich Hickey in 2007 after two years of work. The name Clojure originated in closure of the languages C#, Java and Lisp (CLJ).

It is a stable language with a tiny core. There are amazing libraries and tools which increase the productivity. The basic philosophy of Clojure is simplicity.

Clojure logo

Screenshot (150)

A history of Clojure.pdf

TLDR: Why you should use Clojure?

Rich Hickey - Are We There Yet?

STM primitives for paralelism

Every program needs to preserve the state which changes over time. Clojure does not support variables but gives higher primiteves for working with values changing over time, similarly to SQL databases.

epochal-time-model

Efficient immutable data structures

Clojure works with values which cannot be changed. But it is possible to efficiently create modified values.

Screenshot (152)

Rich Hickey created these data structures so they are efficient enought for 99% of all applications. Time to reading is 1-2x, time of writing is 1-4x. Often, the program can be in total more efficient which is counterintuitive.

Screenshot (153)

Rich Hickey - Clojure, Made Simple

Rich Hickey

rich

Atoms and others

Atoms allow to work with time. They are always pointing to some value. Values cannot be changed but an atom can be atomically updated to point to a different value. Special functions swap! and reset! change values of atoms.

(def a (atom {}))
@a ; => {}
(def b @a)
(swap! a assoc :abc 123)
@a ; => {:abc 123}
b ; => {}

ClojureScript only has atoms because it does not run in parallel. Clojure has further primitives: refs (supporting transactions), agents (asynchronous changes), vars.

Data structures

Supported directly as language primitives using special notation:

These data structures are immutable, very efficient, can contain arbitrary data types and can be arbitrarily nested in each other.

{:source-paths ["src"]
:dependencies [[reagent "1.2.0"]
[re-frame "1.3.0"]
[binaryage/devtools "0.9.10"]]
:nrepl {:port 9000}
:builds {:client {:target :browser
:output-dir "resources/public/js/compiled"
:asset-path "/js/compiled"
:modules {:main {:init-fn example-client.core/init}}
:compiler-options {:infer-externs :auto}
:devtools {:http-root "resources/public"
:http-port 3000
:after-load example-client.core/mount-root
:watch-dir "resources/public"}}}}

Rich Hickey - Simple Made Easy

Rich Hickey - Effective Programs - 10 Years of Clojure

let

The documentation. It allows te define shorthands (called local bindings) which improves readablity and allows a value to be used multiple times. It replaces local variables in most languages. The syntax is:

(let [pair binding-symbol,value]
an arbitrary list of forms)
(let [[x y :as my-point] [5 3]]
(println x y)
(println my-point))
5 3
[5 3]

Sequences

Sequences are abstractions which have the first element and the rest of the sequence. Most functions working with sequences are lazy, so even infinite sequences can be used. For instance, (range) is the infinite sequence of non-negative integers.

All data structures of Clojure can be used as sequences. For instance, a hash map corresponds to a sequence of pairs key-value (in some order). Also Java data structures work as sequences. Basic Clojure functions almost always work with an arbitrary sequence, so the same code can be used for all data structures.

Basic data types

Data oriented programming

The Internet runs on text messages. The formats such as HTTP or JSON are usable by everyone. ORM and other binary formats are not.

An idea of Clojure is to use the same techniques for programming the insides of our systems. So distinct parts of the system communicate via plain data.

Data can be easily printed, analysed, a single set of functions can be applied, the communication is transparent. Transforms are applied on data to change them. The name functional programming wrongly puts the transformations into the fronts, the data are more important.

Comparing

Non-truthy values are nil and false. All other values are truthy: 0, empty collections, etc. Negation is done using not.

Functions =, not= compare values, they work for arbitrary data structures and for an arbitrary number of parameters.

Functions <, <=, >, >= compare numbers. They work for an arbitrary number of parameters: (< 1 2 3 4 5) is true.

Macros and and or accept an arbitrary number of arguments. They return the last/first truthy value. For instance (or val 5) allows to define the default value in the case val is nil.

Generating HTML using data

(def beers (atom 0))

(defn beer-counter [{:keys [name]}]
[:div
[:h1 "Hello, " name]
[:p "You have drank " @beers " beers"]
[:button
{:on-click #(swap! beers inc)}
"Drink a beer"]])

Functions

Functions in Clojure are defined using defn:

(defn myfunc [x y z]
(+ (* x y) z))

Functions are called by placing the function symbol and arguments into a list:

(myfunc 2 3 4)
=> 10

Functions are first-class, so they can be arbitrarily stored or passed as values.

Anonymous functions can be created using fn:

(fn [x y]
(+ x y))

A shorthand notation is available for very simple functions:

#(+ %1 %2)

The parameters are %1, %2, etc. For unary functions, % can be used as the argument.

Intro to language

EDN

EDN (Extensible Data Notation) is a data format used for programming Clojure. The Clojure compiler reads the format and interprets it as a code. EDN is basically an improved JSON to enable support programming. So you don't have to write commas and aside strings also symbols and keywords are supported. It is also possible to define new data types using the so-called reader literals.

when, if, and cond

The forms if, when and cond. It is possible to use them anywhere, even inside a form, so they serve as a more readable ?: operator from C as well.

If contains a test, true form and a false form:

(if (< x y)
x
y)

When contains only the true form of an if form, but it can contain an arbitrary number of forms in it.

(when (< x y)
(println "x is smaller")
x)

Cond allows to have an arbitrary number of branches in an elegant syntax. The first true branch is returned, the rest is ignored:

(cond
(< x y) "x is smaller than y"
(< x z) "x is smaller than z"
:else "x is larger than both y and z")

There are useful shorthands if-not, when-not, if-let, when-let.

Basic functions and macros

Overview of core functions in Clojure and Clojurescript.

Functional programming

Screenshot (144)

map

The high-order function map independently transforms elements of a sequence by the given function.

So (x, y, z, ...) ⇒ (f(x), f(y), f(z), ...).

It even works for multiple input sequences.

(map inc [1 2 3 4])                     ; => (2 3 4 5)
(map #(* %1 %2) [1 2 3 4] [0 1 2 3 4]) ; => (0 2 6 12)

High-order functions

Threading macros

They allow to chain a list of transformations, they work as a pipe. So a value is send to the first transform, the result is send to the second, etc. More information in the documentation.

(->> (range 10)    ; => (0 1 2 3 4 5 6 7 8 9)
(map #(* % %)) ; => (0 1 4 9 16 25 36 49 64 81)
(filter even?) ; => (0 4 16 36 64)
(reduce +)) ; => 120

Object oriented programming

I'm sorry that I long ago coined the term "objects" for this topic because it gets many people to focus on the lesser idea. The big idea is "messaging"

The curse called Haskell

When one say functional programming, most programmers recall Haskell. It had infected academia so students are forced to learn it in university. I personally think that Haskell does big harm to functional programming because it is presented as mysterious and hard to understand. Words such as category theory, monads or functors create the following reaction with most programmers:

fuck math

Clojure is a practical transparent programming language without similar non-sense ideas.

filter a remove

Filtr only keeps elements satisfying a predicate (a unary function) and remove only removes these elements.

(filter odd? [0 1 2 3 4 5 6])  ; => (1 3 5)
(remove odd? [0 1 2 3 4 5 6]) ; => (0 2 4 6)

for

Compared to other languages, the syntax of for is much more powerful but works independently on each sequence element. It returns a sequence of transformed elements.

(for [x [1 2 3 4 5]]
(* 2 x)) ; => (2 4 6 8 10)
(for [x (range 5)
y (range 5)
:when (< x y)
:let [z (+ x y)]]
[x y z])
; => ([0 1 1] [0 2 2] [0 3 3] [0 4 4] [1 2 3] [1 3 4]
; [1 4 5] [2 3 5] [2 4 6] [3 4 7])

An ilustration of OOP

OOP visualised

Rich Hickey: Objects are like marionettes. Whoever having the reference fully controls the object. Nothing works in the real world like this.

Screenshot (141)

An HTTP Request as data

{:remote-addr        "127.0.0.1",
:scheme :http,
:query-params {"somekey" "somevalue"},
:form-params {},
:request-method :get,
:query-string "somekey=somevalue",
:content-type nil,
:uri "/foobaz",
:server-name "localhost",
:params {"somekey" "somevalue"},
:headers {"accept-encoding" "gzip, deflate",
"connection" "close",
"user-agent" "Apache-HttpClient/4.1.2 (java 1.5)",
"content-length" "0",
"host" "localhost:8383"},
:content-length 0,
:server-port 8383,
:character-encoding nil}

reduce

The function reduce. Elements of a sequence are consumed one by one and cummulate into a returned value. The return value is updated in each step by a given binary function applied on the previous return value and the next element in the sequence.

(reduce + (range 10))                ; => 45
(reduce conj #{} [1 3 7 4 8 3 1 7]) ; => #{1 3 7 4 8}

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)

An HTTP Request as an object

Rich Hickey: This is life sucking ...

Screenshot (142)

data are much simpler

Rich Hickey - Death by Specificity

OrgPad is built in Clojure as well :)

Interactive Clojure tutorial

Do you want to learn Clojure? We have build an interactive tutorial for it in OrgPad. Code snippet are running Klipse and it is possible to change them. The results are immediately updated.

REPL

You can imagine REPL (Read-Eval-Print-Loop) as a communication channel between you and a running Clojure program. This allows a lot of amazing things:

This video shows an example of  debugging a simple server using REPL. It feels like having a dialog with your running program.