Setting up your environment for scripting with Clojure

Written by Erhan Bagdemir on January 18, 2014 Categories: Clojure Tags: , , ,

After you step into the Clojure world, an another question you may ask yourself is how you can run the Clojure files just like any other script files (as if they're written in Bash, Perl, Python, etc.) without creating any Leiningen project ? The plugin lein-exec allows you to run your Clojure files without compiling - at least in feeling. There are also a couple of ways to achieve this, please see this Stackover thread. However, the way how lein-exec plugin solves this problem seems more natural and straightforward to me.

I assume that you have already installed Leiningen (version 2.x) to your system. If not, you can follow the installation instructions on leiningen.org.

To install the lein-exec plugin, you need follow the way you already use to install Leiningen plugins. Just add following line into your "~/.lein/profiles.clj":

{:user {:plugins [[lein-exec "0.3.1"]]}}

Your first "lein" call using lein-exec plugin lets Leiningen download and install the plugin to your system:

$ lein exec -e '(println "chuck norris doesn't say hello world.")'

As the example above demonstrates, providing -e option you can even run the Clojure snippets using lein-exec, or run the clj files:

$ lein exec ~/path/to/foo.clj

and adding an alias like "alias 'clj=lein exec'" into your ~/.bashrc, it gets even better:

$ clj ~/path/to/foo.clj

There is one more tip if you want to make Clojure files executable (like a bash script file adding shebang). To do this first download both scripts lein-exec and lein-exec-p and copy the both files into a directory which is in PATH:

$ wget https://raw.github.com/kumarshantanu/lein-exec/master/lein-exec
$ wget https://raw.github.com/kumarshantanu/lein-exec/master/lein-exec-p
$ chmod a+x lein-exec lein-exec-p
$ sudo mkdir /opt/lein-exec
$ sudo mv lein-exec lein-exec-p /opt/lein-exec
$ export PATH=$PATH:/opt/lein-exec # you can add this line into the .bashrc

Now, you're ready to write your first executable Clojure script, hello.clj:


#!/bin/bash lein-exec

(print "Chuck Norris doesn't say Hello!")

To be able to run this script, you need to make it executable and just run as any other scripts as if written in Perl, Python, Ruby, etc. :

$ chmod u+x hello.clj
$ ./hello.clj
Chuck Norris doesn't say Hello!

But, what happens if you have some dependencies to the other libraries like clojure-contrib or clj-http to make some http requests ? Fortunately, lein-exec deals with these dependencies as well. What you need is to declare these libraries at the top of your script using the function "deps" in the leiningen.exec namespace. Here is a basic example which performs an HTTP HEAD request to the blog:

#!/bin/bash lein-exec

; load dependencies required by this script
(require ' [leiningen.exec :o nly (deps) :as lein-exec])
(lein-exec/deps '[clj-http "0.7.8"])

; here is my script
(ns com.bagdemir
(:require 1))

; make a http head request
(print (clj-http.client/head "http://bagdemir.com"))

In my opinion using lein-exec is a very elegant way to write Clojure scripts. With some environment settings and a few lines of code which load all dependencies for you, you can utilize Clojure for your hacks with a scripting ninja motivation.

No Comments

Implementing Relational Algebra in Clojure

Written by Erhan Bagdemir on July 30, 2013 Categories: Clojure, Computer Science

As i was recently reading up on Clojure's sequences, i've noticed that the name of some functions which reside in clojure.set package correspond to the operations in relational algebra. Since i am using my blog page as a notepad, here i'm giving some examples of Clojure's sequence library in order to look up these smart but easy-to-forget functions while ongoing future projects. Here, how you can implement relational algebra in Clojure.

Before i start with the sequences, let me define the following sets which are used in the examples later. Say, we've got two sets of some of well known companies and their founders:

;; first you need to import set operations
(require '1])

;; our set of companies has some infos about them
(def companies-1
   #{{:company "Microsoft" :year 1975 :city "Redmond"}
     {:company "Apple" :year 1971 :city "Cupertino"}
     {:company "Google" :year 1998 :city "Mountain View"}
    })

(def companies-2
   #{{:company "Ford" :year 1903 :city "Detroit"}
     {:company "Apple" :year 1971 :city "Cupertino"}
     {:company "Intel" :year 1968 :city "Mountain View"}
    })

;; founders are associated through ":company" key with the companies set
(def founders
   #{{:name "Bill Gates" :company "Microsoft"}
     {:name "Paul Allen" :company "Microsoft"}
     {:name "Steve Jobs" :company "Apple"}
     {:name "Steve Wozniak" :company "Apple"}
     {:name "Ronald Wayne" :company "Apple"}
     {:name "Larry Page" :company "Google"}
     {:name "Sergey Brin" :company "Google"}
     {:name "Henry Ford" :company "Ford"}
     {:name "Gordon E. Moore" :company "Intel"}
     {:name "Nobert Noyce" :company "Intel"}
   })

The basic operations like union, difference, intersection and rename are very straightforward to implement using set functions:

;; renames :name keys to :first-name
(rename companies-1  {:company :first-name})

;; to find out intersection set of sets, returns :
;; #{:company "Apple" :year 1971 :city "Cupertino"}
(intersection companies-1 companies-2)

;; to union set of companies-1 and companies-2
;; duplicates will be eliminated.
(union companies-1 companies-2)

;; shows the different elements of companies within the first set
;; from the second one, "Google" and "Microsoft"
(difference companies-1 companies-2)

Selection and Projection

So far so good, but Clojure has actually more capability on sets like projection and selection and even join operations like in SQL. For example if you only care about company names in the companies sequence:

;; projection on :company
;; expected output : #{{:company Apple} {:company Google} {:company Microsoft}}
(project companies-1 [:company])

Selection can be implemented using a higher-order functions in select :

;; selects the elements in companies of which name is "Apple":
(select #(= (:company %) "Apple") companies-1)

Here, we're looking for the company of which name is "Apple". I want to remember you that you can use the keys in sets as functions like (:company {:company "Apple"}) as well as in maps.

Join

It's very common to join two tables in relational database world. You can implement join operation in Clojure using "join" function. In the basic usage without providing any keymap, Clojure looks for matching keys in both sets. In our case, join lets the first set join to the second one on the key ":company".

;; basic notation.
(join companies-1 founders)

But, it's also possible to use join on different keys providing a key map. In the following example, we first rename the key :company to :company-name and let both sets join on different keys, ":company-name" and ":company".

;; providing a key map.
(join companies-1 (rename founders {:company :company-name}) {:company :company-name})

Using Operations in Combination

Now, you should've enough intuition to be able to do more complicated things using the whole set functions. Let's try to find the founder names of the companies in both companies set which are established after 1970:

(project
    (select #(> (:year %) 1970)
         (join (union companies-1 companies-2) founders)) [:company]))

As a first step, we merge both sets into a big one which contains the whole companies from both company sets and join that to the founders set on the key ":company". After that, we perform a selection operation on the result set using a lambda which filters out the companies established before 1970. As a last step, we perform projection in order to return just the company names.

Cross Product

The last operation on sets is the cross product:

(for [c1 companies-1 c2 companies-2] (concat c1 c2))

Using for macro we can combine multiple sets and create cross products. If you've got some experience in Scala, it is similar to following example:

for (c1 <- companies1; c2 <- companies2) yield (c1, c2)

I think it's all i wanted to explain about set operations in Clojure.
They're very smart immutable functions which you can do much more using them in combination.
For more functions for Sets you can refer to clojure.set.

No Comments