Getting Started with Clojure

0
4168

Getting Started with Clojure

The flexibility and simplicity offered by this programming language, which is hosted on the Java Virtual Machine, is bound to make it very popular among developers

.Clojure is a dynamically and strongly typed programming language, created by Rich Hickey and hosted on the Java Virtual Machine. It was formed by incorporating the finest features of a variety of programming languages, such as Python, Java, Haskell, etc. Clojure helps eliminate various issues faced by the programmer, while setting them right for the future. Hickey developed Clojure because he felt the need to develop a modern LISP for functional programming. The simple syntax that it has makes meta programming through macros extremely simple.

Why Clojure?
The best part about Clojure is that it is hosted on JVM, which has an efficient runtime environment. Hence, it would be better to choose Clojure rather than select a completely new language and work in a completely new environment. The other reasons to choose Clojure include:

  • The great flexibility and strong metaprogramming facilities it has, due to its LISP origins.
  • The remarkable concurrency and parallelism semantics that it provides.
  • The presence of persistent data structures whose performance puts even the mutable data structures to shame.
  • It’s very useful when it comes to dealing with large amounts of data, because of which it is extensively used in data mining and large scale predictions.
  • Clojure’s reference types ensure a clear separation between state and identity, and help provide defined concurrency semantics to manual threading and locking strategies.
  • It is very efficient when it comes to programming to small interfaces.
  • Clojure is dynamically and strongly typed but when it comes to compiling, it’s compiled to Java method invocations, which makes it fast.
  • It offers a safe and simple method to handle mutability.
  • The manner in which it models data makes it easy to work on.
  • The REPL in Clojure has no runtime penalty and, hence, is faster in comparison to its counterparts.

Setting up Clojure
We need not install Clojure as such, but we need a build tool capable of managing dependencies. The most recommended build tool is leningen. By following the steps mentioned below, you can easily set up leningen:
1. Confirm that you have a Java development kit (JDK) version 6 or higher.
2. Download the lein script from the most stable version of the project. (Refer leningen.org for more information)
3. Place it in your $PATH.
4. Make it executable.
5. Run it.

Figure 1
Figure 1 : What a REPL for clojure looks like

A few simple programs in Clojure
Here, let’s look at two simple examples.
1. Hello world

Type the following command in a terminal:

$ lein repl

You’ll get something similar to what is shown in Figure 1.
Now type the following command and press Enter. Notice how it’s similar to the System.out.println familiar to all in Java.

user=> (println “Hello World!”)

You’ll get the output as:

user=> (println “Hello World!”)
Hello World!
nil

2. Defining two variables and finding their sum
The following code defines two variables and stores their sum in yet another variable:

user=> (def a 432)
#'user/a
user=> (def b 123)
#'user/b
user=> (def c (+ a b))
#'user/c
user=> c
555
user=>

What are namespaces?
Namespaces are usually used to group symbols and identifiers around a particular functionality.
Clojure has a large amount of namespaces and they all come with many functions, thus making Clojure easy to use.
clojure.github.io/clojure gives the details of the functions and vars present in each namespace in Clojure, as well as their documentation.
We can change the namespace we want to use by giving the ‘require’ command in REPL. After using the ‘require’ command, just use the namespace name while referring to any function/variable described inside it.
The most recommended way to set up a new namespace at the top of a Clojure source file is to use the ns macro. By default, this will create a new namespace that will contain the mappings for classnames in java.lang and the functions in clojure.core.

Data structures in Clojure
Maps, vectors, sets and lists are the basic data structures that Clojure provides; the other data structures are present in Clojure collection hashes, StructMaps, ArrayMaps, etc.
In Clojure, there are seven primary abstractions whose data structures are as follows.

1. Collection: All data structures in Clojure follow the common collection abstraction. A collection is a value that you can use with the set of core collection functions.
* conj is used to add an item to a collection:

user=> (conj ‘(237 4 2) 5)
(5 237 4 2)

* seq is to get a sequence of a collection:

user=> (seq ‘(1 2 3) )
(1 2 3)

* count helps in getting the number of items in a collection:

user=> (def a (seq ‘(1 2 3 4 5 6))
#’user/a
user=>(count a)
6

* empty is used to obtain an empty instance, which has the same type as that of the collection:

user=> (def a (empty ‘[1 2 3 4]))
#’user/a
user=> a
[]

* = is used to check equality between one collection and another completely different collection:

user=> (= ‘[1 2 3] ‘[1 2 3])
true
user=> (= ‘[1 2 3] ‘(1 2 3))
true
user=>(= ‘[1 2 3] 1)
false

2. Sequence: The sequence abstraction shows a way for traversal on sequential views over some set of values —either another collection or values that are the result of some calculation. There are a few operations that sequences undergo:

  • seq produces a sequence over its argument.
  • The first, next and rest of the keywords help make traversal through the seq an easy task.
user=> (def a (seq '(1 2 3 4 5 6 7)))
#'user/a
user=> (first a)
1
user=>(rest a)
(2 3 4 5 6 7)
  • It is possible for the contents of a sequence to be evaluated at leisure, where values are computed and produced only when a user tries to access it.

3. Associative: The associative abstraction is found in all data structures that map keys to certain values in some way; so, it is mostly seen in various kinds of maps. It has four operations:

  • assoc, through which connections are made between a key and its value:
user=> (def S {:a 10 :b 20 :c 30})
#'user/S
user=> (assoc S :d 40)
{:a 10 :b 20 :c 30 :d 40}
  • dissoc, which cuts off the connections between a key and its value:
user=> (def S {:a 10 :b 20 :c 30})
#'user/S
user=> (dissoc S :a )
{:b 20 :c 30}
  • get, which searches the value for a specific key in the collection:
user=> (def S {:a 10 :b 20 :c 30})
#'user/S
user=> (get S :a)
10
  • contains?, which checks if a key has a specific value and returns true if it does:
user=> (def S {:a 10 :b 20 :c 30})
#'user/S
user=> (contains? S :a )
true

4. Indexed: The index abstraction here is similar to the one in C++. The index can be given to access an element present at that specific position. There is only one function here, nth, which acts like the get function and returns the element at the nth position. There are also exceptions to check the out-of-bounds condition.

user=> (def S '[1 2 3 4 5])
#'user/S
user=> (nth a 2)
3

5. Stack: Clojure does not have a stack data structure as such, but we can use lists and vectors to realise this data structure. The three main operations here are:

  • conj, to add an element to the top of the stack:
user=> (def stack '(5 4 3 2 1))
#'user/stack
user=> (conj stack 6)
(6 5 4 3 2 1)
  • pop, to remove the element present at the top of the stack:
user=> (def stack '(5 4 3 2 1 ))
#'user/stack
user=> (pop stack )
{4 3 2 1}
  • peek, for obtaining the value on the top of the stack:
user=> (def stack '(5 4 3 2 1))
#'user/stack
user=> (peek stack)
5

6. Set: The set abstraction is technically a reusing of the functions in a collection as well as associative semantics. The clojure.set namespace provides a number of functions that can be performed on a set, including subset?, superset?, union, etc.

user=> (require '[clojure.set :as t])
nil
user=> (def a '[1 2 3 4 5 6 7 8])
#'user/a
user=>(def b '[1 2 3])
#'user/b
user=>(t/subset? b a)
true
user=>(t/superset? a b)
true
user=>(t/union a '[9 10 11])
[1 2 3 4 5 6 7 8 9 10 11]

7. Sorted: Collections that follow sorted abstraction are assured that their elements will be sorted. Only maps and sets are available in the sorted variant. The main functions here are as follows.

  • rseq, which returns the sequence in the reverse order:
user=> (vec (range 16))
[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16]
user=> (rseq (vec (range 16)))
(15 14 13 12 11 10 9 8 7 6 5 4 3 2 1)
  • subseq, which returns a subseq that’s in a particular order:
user=> (subseq (sorted-set 1 2 3 4 5 6 7 8) > 4)
( 5 6 7 8)
  • rsubseq, which is the same as subseq, but in reverse order:
user=>(rsubseq (sorted-set 10 20 30 40 50) < 29)
(20 10)

What next?
ClojureCLR: ClojureCLR1 is a port of Clojure to the .NET CLR. It is not a simple cross-compilation; rather, it is maintained separately and aims at providing the same level of usability for CLR as it provides for JVM. Even though ClojureCLR is not as widely used as Clojure, it’s well-tested and provides a lot of options for anyone who wishes to work on it.

ClojureScript: ClojureScript (github.com/clojure/clojurescript) is mainly targeted at JavaScript (technically, ECMAScript 3), and therefore produces code that can be run in all the latest browsers, as well as in other environments that execute JavaScript such as Node.js, CoffeeScript, etc. There is a big difference between Clojure and ClojureScript. This is not only because there is a major difference between the hosts for JavaScript and the JVM, but also due to the fact that ClojureScript is a source-to-source compilation. An overview of the differences between Clojure and ClojureScript is available at github.com/clojure/clojurescript/wiki/Differences-from-Clojure.

Though Clojure has not reached its zenith of success and popularity yet, it’s pretty certain that it will do so in a couple of years. Many of the core companies have started adding Clojure to the pre-requisites candidates need to have when it comes to recruiting. So, we can say with certainty that Clojure is indeed the future.

References
[1] clojure.org
[2] stackoverflow.com3.
[3] ‘Clojure in Action’ by Amit Rathore
[4] ‘Clojure Programming’ by Chas Emerick, Brian Carper and Christophe Grand

LEAVE A REPLY

Please enter your comment!
Please enter your name here