Getting Started with Clojure

February 01, 2016
Written by

GettingStartedWithClojureFeatured

JavaScript has been my go-to language for quite some time now and before that it was Ruby. Both of these languages have a lovely dash of functional programming that I’ve toyed with here and there. It seems functional concepts are becoming more and more prominent amongst the JS community with projects like Redux and Immutable.js gaining popularity. I recently decided to take the dive into functional programming. A friend recommended the Clojure programming language and learning it has been a real hoot.

owl.gif

Clojure was created by Rich Hickey who had a very strong rationale for its birth. The language is designed to compile down to bytecode and run on a virtual machine so it’s not OS dependent. The JVM is the the most popular target but it can also compile down to JavaScript or the Microsoft CLR. Thanks to strong interoperation support you can easily take advantage of your target platform’s host language and features. We’ll see an example of this later on.

In this post we’re going to start with the basics of Clojure and its de facto build tool Leiningen. We’ll wrap up by sending our first SMS with Clojure.

I’m absolutely still an apprentice so feel free to help out below in the comments if something can be improved. I’ve found that the Clojure community is super friendly and willing to help. Heck the language is community developed.

Time To Get Technical

Let’s start by installing Leiningen. Not only does it have the best mascot logo but might just be the best build tool I’ve ever used.

The Clojure compiler is actually just a JAR file and Leiningen will take care of downloading it and doing all the heavy javac flag and classpath lifting.

Follow the instructions based on your platform. There is also an installer for Windows and a Homebrew formula if you’re on a Mac.

We can confirm it’s installed by running the following.

lein repl

This will start up a Clojure Read Eval Print Loop (REPL) and give you a nice little prompt.

Clojure is a lisp which means it uses tons of parenthesis and prefix notation. Calls to functions start with the name of the function and then the arguments. So to use the + function to add 2 + 2 we can type the following into our REPL.

(+ 2 2)
; 4

This construct is called a form and the “words” inside of it are known as symbols. We can easily chain forms by adding more parenthesis.

(+ 2 (+ 2 2))
; 6

Notice we don’t need to use commas to separate symbols – they are optional and treated as whitespace. The syntax will take some getting used to but I’ve found it to be very expressive.

The native data structures are powerful and are used everywhere. The most common we’ll be using are the vector and the map.

The vector is what we might think of as an array. It is a list of elements enclosed in square brackets. [1 2 3 "a" "b" "c"]. We can generally ask for the first item out or the rest to perform a recursive operation on the vector.

(first [1 2 3])
; 1

(rest [1 2 3])
; (2 3)

We can also access an element at an index using the get function.

(get ["Cats" "Dogs" "Fish"] 1)
; Dogs

Let’s iterate over a vector and call a function on each element using doseq. This function expects a symbol and a collection that it will iterate over and bind to the symbol. It then calls your provided form for each item. We’re also using the println function which, as you guessed, prints a line to the console along with the str function which concatenates strings.

(doseq [name ["Betty" "Sue" "Amy"]]
  (println (str "Hello, " name)))
; Hello, Betty
; Hello, Sue
; Hello, Amy
; nil

The map is our dictionary structure in Clojure. It’s created with curly braces and a set of keys and values separated by whitespace. This one’s a little tricky to get used to since we’re not visually associating the key and the value.

(get {"name" "Bob Barker" "game" "The Price is Right"} "name")
; "Bob Barker"

It’s common to use Clojure keywords as the key for a map. A keyword is a symbolic identifier that evaluates to itself. We denote a keyword with a colon.

(get {:name "Bob Barker" :game "The Price is Right"} :game)
; The Price is Right

Since this is so common we can actually use the keyword as a function and pass it a map to pull out the value.

(:name {:name "Bob Barker" :game "The Price is Right"})
; Bob Barker

The last building block we’ll learn is how to define our own function. To do this we use the defn macro. The form of this is (defn name-of-function [args] (body)). The following function say-hello will take a name and print out a personalized greeting.

(defn say-hello
  [name]
  (println (str "Hello, " name)))

(say-hello "Mary Poppins")
; Hello, Mary Poppins
; nil

Our function can take an undefined number of arguments using the & operator. This causes all the arguments passed in to be squished into one variable as a collection.

(defn say-hello
  [& people]
  (doseq [person people] (println (str "Hello, " person))))

(say-hello "Albert Einstein" "Grace Hopper" "Ada Lovelace")
; Hello, Albert Einstein
; Hello, Grace Hopper
; Hello, Ada Lovelace
; nil

Finally let’s have a go at the Java interoperation that’s available. We’ll use Java’s Date class to get the current time. To do this in Java you’d run the following.

System.out.println(new java.util.Date());

In Clojure we pass the full path and package name to the new function.

(new java.util.Date)
; #inst "2015-11-09T22:29:37.530-00:00"

This is done so much that there is a nice shortcut around it. Note the trailing ..

(java.util.Date.)
; #inst "2015-11-09T22:29:37.530-00:00"

We can call methods on the returned object with the .methodToCall function.

(.toString (java.util.Date.))
; Mon Nov 09 18:18:24 EST 2015

; This syntax comes from the base `.` function

(. (java.util.Date.) toString)
; Mon Nov 09 18:18:55 EST 2015

Even better, if we want to chain a bunch of Java method calls the .. function makes this easy.

(.. (java.util.Date.) toString toUpperCase)
; MON NOV 09 18:19:06 EST 2015

Hello, World!

We now have enough of a basis to create our first Clojure app. We’ll leave the REPL and use Leiningen to generate our skeleton. The quit command should take you out of the REPL.

Create a new directory where you want to work and cd to it in your shell. Now let’s unleash Leiningen on our new directory and have it create a blank app project for us.

lein new app hello-clojure
cd hello-clojure

There are two files in here that we’ll be working with. The first is project.clj which is our build file for Leiningen and the second is our source file at src/hello_clojure/core.clj. We’ll come back to the build file in a bit but for now let’s open up the source file in your favorite editor.

The top two lines set up our namespace and tell the compiler to generate a class for our app since Java uses classes and we’re running on the JVM. Following that is our main function definition which is the entry point to our app. The string after the declaration is used to document what this function does. The rest should look familiar from above.

(ns hello-clojure.core
  (:gen-class))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (println "Hello, World!"))

We can tell Leiningen to compile and run our application by running

lein run
# Hello, World

Even better we can painlessly build an uberjar that we can distribute and run on a standard JVM.

lein uberjar
# Compiling hello-clojure.core
# Created /Users/ezaneski/Codez/hello-clojure/target/uberjar uberjar/hello-clojure-0.1.0-SNAPSHOT.jar
# Created /Users/ezaneski/Codez/hello-clojure/target/uberjar/hello-clojure-0.1.0-SNAPSHOT-standalone.jar
java -jar target/uberjar/hello-clojure-0.1.0-SNAPSHOT-standalone.jar
# Hello, World

Wow that was absurdly easy.

Sending an SMS

Our program is rad but doesn’t do much. Let’s fix that by making it send a text message using the Twilio API. You’ll need your Twilio account credentials and a Twilio phone number. If you don’t have an account yet you can sign up for a free one here.

An awesome community member has created a Twilio Clojure library that makes sending an SMS a breeze. To add the dependency to our app open up project.clj And add [twilio-api "1.0.1"] to the :dependencies vector.

(defproject hello-clojure "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.7.0"]
                 [twilio-api "1.0.1"]]
  :main ^:skip-aot hello-clojure.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

We can have Leiningen download the dependency by running the following.

lein deps

Open up core.clj again and replace it with the following. You’ll notice a that we’re using an @ in front of the call to twilio/send-sms. It’s a bit out of the scope of this post but that’s actually a shortcut for the deref function which causes our program to block and wait for an asynchronous operation to complete – such as the HTTP request to Twilio’s API. If we don’t block on the HTTP request, the program will stop running before it’s made due to it being asynchronous.

(ns hello-clojure.core
  (:require [twilio.core :as twilio])
  (:gen-class))

(defn -main
  [& args]
  (twilio/with-auth "YOUR_TWILIO_ACCOUNT_SID" "YOUR_TWILIO_AUTH_TOKEN"
    @(twilio/send-sms
       {:From "YOUR_TWILIO_PHONE_NUMBER"
        :To "YOUR_PHONE_NUMBER"
        :Body "Hello from Clojure!"})))

Run the code one last time and take out your phone.

lein run

7e0EvlBD7nxZu

Next Steps

We’ve explored some of the basics of Clojure and seen how we can take advantage of the Java interop. We also wrote a function that sends an SMS using an stellar community created library. I think we can all agree that Leiningen lives up to its tagline of “… automating Clojure projects without setting your hair on fire”.

Hopefully this post has inspired you to give Clojure a try. It is a much different paradigm but pretty fun to work with.

For more reading and learning check out the book Clojure for the Brave and True by Daniel Higginbotham. And the Clojure from the ground up blog post series by Kyle Kingsbury.

Be sure to let me know what your thoughts on the language are!

Twitter: @eddiezane