In order to understand the basic syntax of Clojure, let’s first look at a simple Hello World program.
Write ‘Hello world’ in a complete Clojure program. Following is an example.
(ns clojure.examples.hello (:gen-class)) (defn hello-world [] (println "Hello World")) (hello-world)
The following things need to be noted about the above program.
The program will be written in a file called main.clj. The extension ‘clj’ is the extension name for a clojure code file. In the above example, the name of the file is called main.clj.
The ‘defn’ keyword is used to define a function. We will see functions in details in another chapter. But for now, know that we are creating a function called helloworld, which will have our main Clojure code.
In our Clojure code, we are using the ‘println’ statement to print “Hello World” to the console output.
We then call the hello-world function which in turn runs the ‘println’ statement.
The above program produces the following output.
Hello World
The general form of any statement needs to be evaluated in braces as shown in the following example.
(+ 1 2)
In the above example, the entire expression is enclosed in braces. The output of the above statement is 3. The + operator acts like a function in Clojure, which is used for the addition of numerals. The values of 1 and 2 are known as parameters to the function.
Let us consider another example. In this example, ‘str’ is the operator which is used to concatenate two strings. The strings “Hello” and “World” are used as parameters.
(str "Hello" "World")
If we combine the above two statements and write a program, it will look like the following.
(ns clojure.examples.hello (:gen-class)) (defn Example [] (println (str "Hello World")) (println (+ 1 2))) (Example)
The above program produces the following output.
Hello World 3
A namespace is used to define a logical boundary between modules defined in Clojure.
This defines the current namespace in which the current Clojure code resides in.
*ns*
In the REPL command window run the following command.
*ns*
When we run the above command, the output will defer depending on what is the current namespace. Following is an example of an output. The namespace of the Clojure code is −
clojure.examples.hello (ns clojure.examples.hello (:gen-class)) (defn Example [] (println (str "Hello World")) (println (+ 1 2))) (Example)
Clojure code is packaged in libraries. Each Clojure library belongs to a namespace, which is analogous to a Java package. You can load a Clojure library with the ‘Require’ statement.
(require quoted-namespace-symbol)
Following is an example of the usage of this statement.
(ns clojure.examples.hello (:gen-class)) (require ‘clojure.java.io’) (defn Example [] (.exists (file "Example.txt"))) (Example)
In the above code, we are using the ‘require’ keyword to import the namespace clojure.java.io which has all the functions required for input/output functionality. Since we not have the required library, we can use the ‘file’ function in the above code.
Comments are used to document your code. Single line comments are identified by using the ;; at any position in the line. Following is an example.
(ns clojure.examples.hello (:gen-class)) ;; This program displays Hello World (defn Example [] (println "Hello World")) (Example)
In Clojure, statements can be split or delimited by using either the curved or square bracket braces.
Following are two examples.
(ns clojure.examples.hello (:gen-class)) ;; This program displays Hello World (defn Example [] (println (+ 1 2 3))) (Example)
The above program produces the following output.
6
Following is another example.
(ns clojure.examples.hello (:gen-class)) ;; This program displays Hello World (defn Example [] (println [+ 1 2 3])) (Example)
The above program produces the following output.
[#object[clojure.core$_PLUS_ 0x10f163b "clojure.core$_PLUS_@10f163b"] 1 2 3]
Whitespaces can be used in Clojure to split different components of a statement for better clarity. This can be done with the assistance of the comma (,) operator.
For example, the following two statements are equivalent and the output of both the statements will be 15.
(+ 1 2 3 4 5) (+ 1, 2, 3, 4, 5)
Although Clojure ignores commas, it sometimes uses them to make things easier for the programmer to read.
For instance, if you have a hash map like the following (def a-map {:a 1 :b 2 :c 3}) and ask for its value in the REPL window, Clojure will print the output as {:a 1, :b 2, :c 3}.
The results are easier to read, especially if you’re looking at a large amount of data.
In Clojure, symbols are equivalent to identifiers in other programming languages. But unlike other programming languages, the compiler sees symbols as actual string values. As a symbol is a value, a symbol can be stored in a collection, passed as an argument to a function, etc., just like any other object.
A symbol can only contain alphanumeric characters and ‘* + ! / . : - _ ?’ but must not begin with a numeral or colon.
Following are valid examples of symbols.
tutorial-point! TUTORIAL +tutorial+
Finally let’s talk about a typical project structure for a Clojure project. Since Clojure code runs on Java virtual machine, most of the project structure within Clojure is similar to what you would find in a java project. Following is the snapshot of a sample project structure in Eclipse for a Clojure project.
Following key things need to be noted about the above program structure.
demo_1 − This is the package in which the Clojure code file is placed.
core.clj − This is the main Clojure code file, which will contain the code for the Clojure application.
The Leiningen folder contains files like clojure-1.6.0.jar which is required to run any Clojure-based application.
The pom.properties file will contain information such as the groupId, artifactId and version of the Clojure project.
The project.clj file contains information about the Clojure application itself. Following is a sample of the project file contents.
(defproject demo-1 "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.6.0"]])