Clojure

Clojure code is made up of Clojure data structures. The primary one being a list. A list is a collection the elements of which can be accessed sequentially.

brew install lein
lein repl

The Clojure compiler will evaluate the code as is.

(+ 1 2 3 4)

The above is a Clojure data structure, a list, it is also valid source code. The first element of the list is a symbol (variable), followed by arguments. In this case the + symbol is bound (assigned) to a function which accepts an unlimited number of arguments.

Because Clojure code is made up of lists, where the first element is expected to be a symbol it means that when we want to use a list of data we need to let the compiler not to evaluate it.

(+ 1 2) is a list and it is evaluated as code. But what if you want an actual list in your programe, to signal to the compiler that you don’t want the list to be evaluated as part of the program use quote.

(quote (1 2 3))

The above will yield a list, (1 2 3). Without quote the compiler would try to evaluate 1 as a symbol.

(quote (1 2 3)) is a literal list, whereas (1 2 3) is a list which is evaluated as a program, since 1 isn’t a symbol an error ocurrs.

A syntax sugar for quote is '.

Lists

You can not access any element, only head and tail. Therefore access to elements is sequential, there is no random access.

You can thus access any element by getting the head or tail x number of times, but access is sequential.

(list 1 2 3)

(quote (1 2 3))

(1 2 3)

(first 1 2 3) ; 1
(last 1 2 3)  ; 3

There is no equivalent in Ruby. The closest would be any Array for which random access using [] is not allowed.

A List behaviour is a subset of a Vector.

We can get any element, but to do this we have to iterate sequentially through the list. This will have performance issues for very large lists.

(nth (list 1 2 3 4 5 6) 5) 

Vectors

Vectors are like list but with random access to the elements, not just sequential access.

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

[1 2 3]
; [1 2 3]

These are like an Array in Ruby, [1,2,3].

Vectors and Lists are usually interchangeable.

(get [1 2 3] 1] ; get the nth element

(conj [1 2 3] 4)
[1 2 3 4]
[1 2 3].push(4)
[1 2 3] << 4

The important difference is in Clojure, unlike Ruby, everything is immutable.

Using lists

(+ 1 2 3)
; 6

This is a list, the first element is an operator. The remaining elements numbers. In this example each number is an argument to the + function, which can accept any number of arguments.

It looks like inject/reduce in Ruby, but it is not.

[1, 2, 3].reduce(:+)
# 6

This is more like:

(reduce + '(1 2 3))
; 6

In the above reduce is given a function, +, and a collection, the list, (1 2 3). The prefix ' prevents the list being evalutaed as Clojure source.

Anonymous functions

(fn [x] (* x x)
lambda { |x| x * x }

To use this function:

(def square (fn [x] (* x x)))
(square 10) ; 100
square = lambda { |x| x * x }
square.call(10) # 100
square[10]      # 100

Reverse a collection:

(def reverse (fn [x] (reduce conj '() x)))
(reverse [1 2 3]) ; [3 2 1]

Explained:

conj will append to a collection.

reduce takes a function and a starting value and a collection.

Symbols (Varibles)

Variables are scoped to the current namespace and can be accessed anywhere within the namespace.

(def name Kris)

In the above name is referred to as a symbol. And we bind the string “Kris” to it.

name = Kris

Named functions

We can assign an anon function to a variable.

(def square (fn [x] (* x x))

(square 3)
; 9

The above is a list, the argument list is another list.

square = lambda { |x| x * x }

square.call(10)
square[10]

We can use some sugar, using defn, to make this a little more terse:

(defn square [x] (* x x))
(square 4) ; 16

defn can also also accept a doc-string:

(def square “Squares the given number” x)

You can view the doc-string in the REPL: (doc square).

In Ruby defining a method is also simialr:

# squares the given number
def square(x)
  x * x
end

square(10)

Defining local variables

(def my-function [x]

)

Other collections

Map

(hash-map :first_name Kris :last_name Leech)

{:name Kris :last_name Leech }

(:first_name {:first_name Kris :last_name Leech }) 


(def person {:first_name Kris :last_name Leech })

(:first_name person)

:foo is called a keyword in Clojure, like a symbol in Ruby, but not really…

A keyword is in fact a function which looks its self up in the given hash-map.

This is why we can do (:first_name person), :first_name is a function and the argument is person. Mind blown.

You can also lookup a value using get: (get { :first_name ‘Kris’ }).

Ruby: {:name “Kris” :last_name “Leech” }

person = {:name “Kris” :last_name “Leech” }

person[:first_name]

In Clojure you get nested values with get-in:

(get-in { :person { :first_name ‘Kris’ } } [:person :first_name])

In Ruby: params[:person][:first_name]

Set

(set [1 2 3])

#{1 2 3}

(sorted-set [4 10 1 3]) ; #[1 3 4 10}

(get (set 1 2 3) 2) ; 2

(get (set 1 2 3) 100) ; nil

As with hash-map we can use a keyword (which is actually a function which looks itself up in the given collection): (:a (set [:a :b :c]))

Ruby:

Set.new([1,2,3]) [1,2,3].to_set

Namespaces

Like modules in Ruby

map / reduce

map is a higher order function, this means one of its arguments is another function.

(map inc [0 1 2 3])

Ruby:

inc = Proc.new { |n| n + 1} [0,1,2,3].map(&inc)

(map str ‘(1 2 3)) ; map fn collection [1, 2, 3].map(&:to_s) # collection map fn

select / reject

filter takes a function which must return true/false and a collection:

(filter #(> % 5) ‘(3 4 5 6 7))

Ruby: [3, 4, 5, 6, 7].select { |n| n > 5 }