Playing with Clojure

3 minute read

Overview

Clojure is a dialect of the Lisp programming language that has long been known by the free software community, but Clojure runs on the Java Virtual Machine JVM, and has conquered corporate environments precisely by maintaining compatibility with JAVA and being a pure language functional.

I’ve already studied and worked with various programming languages, but what struck me the most in Clojure is its almost alien syntax, I remembered the movie the Predator, great.

  • Clojure is an alien dialect

Screen1

1. Installing

I used FreeBSD to make this article, so to install Clojure on FreeBSD simply type in the terminal the commands:

pkg install clojure leiningen 

In the above command we installed Clojure and Leiningen to automate projects.

1.1 Start

Open another terminal session and enter the command lein repl:

lein repl

nREPL server started on port 23024 on host 127.0.0.1 - nrepl://127.0.0.1:23024
REPL-y 0.3.7, nREPL 0.2.12
Clojure 1.8.0
OpenJDK 64-Bit Server VM 1.8.0_172-b11
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

user=> 

Ok, now it’s possible for you to type the code in clojure and see the results.

user=> (println "Hello World")
Hello World
nil
user=> 

All interaction with clojure starts with parentheses (…), as we can see we did a classic Hello World using the function println and it returns nil equivalent to a void or null.

1.2 Creating Functions

To create functions we use defn:

user=> (defn sigma [x y]
  #_=> (+ x y))
#'user/sigma
user=> 

If you wanted to multiply for example, just use the * operator or to divide /.

You can use the TAB to fill in commands automatically. Another example, looking for the intersection of the two vectors:

user=> (clojure.set/intersection #{:a :b :c} #{:b :a :d})
#{:b :a}

1.3 Using reduce, map, filter

Reduce syntax:

user=> (reduce + 0 '(1 2 3 4 5 6 7 8 9 10))
55

user=> (reduce * 1 '(1 2 3 4 5 6 7 8 9 10))
3628800

Map syntax:

user=> (map inc [1 2 3])
(2 3 4)

user=> (map str ["a" "b" "c"] ["A" "B" "C"])
("aA" "bB" "cC")

Filter syntax:

user=> (def human-version
  #_=> [{:v 1.0 :day 100} 
  #_=>  {:v 2.0 :day 5}
  #_=>  {:v 1.5 :day 10}])
#'user/human-version

user=> (filter #(< (:v %) 2) human-version)
({:v 1.0, :day 100} {:v 1.5, :day 10})

1.4 More advanced Lazy Seqs

Let’s create a fictional alien database:

(def alien-database
  {0 {:makes-blood-puns? false, :has-pulse? true  :name "Predator"}
   1 {:makes-blood-puns? false, :has-pulse? true  :name "Alien"}
   2 {:makes-blood-puns? true,  :has-pulse? false :name "E.T"}
   3 {:makes-blood-puns? true,  :has-pulse? true  :name "Yoda"}})

(defn alien-related-details
  [social-security-number]
  (Thread/sleep 1000)
  (get alien-database social-security-number))

(defn alien?
  [record]
  (and (:makes-blood-puns? record)
       (not (:has-pulse? record))
       record))

(defn identify-alien
  [social-security-numbers]
  (first (filter alien?
                 (map alien-related-details social-security-numbers))))

Let’s see how long it takes to execute the function below:

user=> (time (alien-related-details 0))
"Elapsed time: 1021.035913 msecs"
{:makes-blood-puns? false, :has-pulse? true, :name "Predator"}

Creating a range:

user=> (time (def mapped-details (map alien-related-details (range 0 1000000))))
"Elapsed time: 0.182146 msecs"

Considerations

Clojure is a very cool language to work on, at least it was my first impression, predicting to do other more advanced language tutorials, possibly using clojure for data analysis.