SlideShare ist ein Scribd-Unternehmen logo
1 von 67
Downloaden Sie, um offline zu lesen
@ 2010 by Satish Talim
Prepared exclusively for Clojure 101 Course participants


Clojure for Beginners

Copyright (c) 2010 Satish Talim
http://satishtalim.com/


Warning and Disclaimer

Every effort has been made to make this book as complete and as accurate as possible, but no
warranty of fitness is implied. The information provided is on an "as is" basis. The author shall
have neither liability nor responsibility to any person or entity with respect to any loss or
damages arising from the information contained in this book.




Revised Edition – 27th May 2010
First Edition – May 2010




PLEASE SUPPORT RUBYLEARNING.COM




@ 2010 by Satish Talim                                                                    Page 2
Prepared exclusively for Clojure 101 Course participants




Clojure Notes
Contents
Acknowledgements .................................................................................................................................... 8

ABOUT THE EBOOK ................................................................................................................................... 10

   Assumptions ............................................................................................................................................................................. 10

   Concept and Approach ........................................................................................................................................................ 10

   How to Use This Clojure eBook ....................................................................................................................................... 10

   About the Conventions Used in This Clojure eBook .............................................................................................. 11

   Learn Clojure Online and for Free.................................................................................................................................. 11

INTRODUCTION TO CLOJURE .................................................................................................................... 12

   What is Clojure? ...................................................................................................................................................................... 12

GETTING STARTED .................................................................................................................................... 14

   Labrepl Download and Installation (for MS Windows)....................................................................................... 14

       What's Labrepl? ................................................................................................................................ 14

       Downloading and Installing Labrepl (for MS Windows) .................................................................... 14

       Starting the REPL ............................................................................................................................... 15

       Loading a file in the REPL .................................................................................................................. 16

   Clojure Box Download and Installation (for MS Windows) .............................................................................. 16

       Test if Clojure Box works ................................................................................................................... 17

       Loading a file in Clojure Box .............................................................................................................. 17

   NetBeans/Enclojure Download and Installation (for MS Windows) ............................................................ 18

       To create a Clojure Project in NetBeans............................................................................................ 19

@ 2010 by Satish Talim                                                                                                                                                            Page 3
Prepared exclusively for Clojure 101 Course participants


       To start the REPL in NetBeans ........................................................................................................... 19

       Anatomy of the Enclojure REPL Panel ............................................................................................... 19

   Syntax .......................................................................................................................................................................................... 19

   Comments .................................................................................................................................................................................. 19

   Clojure Coding Guidelines & Naming Convention ............................................................................................. 20

   Forms ........................................................................................................................................................................................... 21

   Symbols ....................................................................................................................................................................................... 21

   Vars and Bindings.................................................................................................................................................................. 22

   Literals......................................................................................................................................................................................... 23

       Booleans and nil ................................................................................................................................ 23

       Numbers ........................................................................................................................................... 23

       Characters and Strings ...................................................................................................................... 25

       Keywords .......................................................................................................................................... 26

   Exercises ..................................................................................................................................................................................... 26

       Exercise 1 .......................................................................................................................................... 26

       Exercise 2 .......................................................................................................................................... 27

CHARGING AHEAD .................................................................................................................................... 28

   A Quick look at Collections ................................................................................................................................................ 28

       Lists ................................................................................................................................................... 28

       Vectors .............................................................................................................................................. 29

       Sets ................................................................................................................................................... 29

       Maps ................................................................................................................................................. 30

       Some functions on collections .......................................................................................................... 31

   Sequences .................................................................................................................................................................................. 32

       seq .................................................................................................................................................... 32

@ 2010 by Satish Talim                                                                                                                                                                   Page 4
Prepared exclusively for Clojure 101 Course participants


       first.................................................................................................................................................... 32

       rest .................................................................................................................................................... 33

       cons................................................................................................................................................... 33

       next ................................................................................................................................................... 33

       conj, into ........................................................................................................................................... 34

       range ................................................................................................................................................. 34

       repeat ............................................................................................................................................... 34

       iterate, take ...................................................................................................................................... 34

       concat ............................................................................................................................................... 35

   Flow Control ............................................................................................................................................................................. 35

       if, if-not ............................................................................................................................................. 36

       cond, condp ...................................................................................................................................... 36

       when, when-not ................................................................................................................................ 37

       do ...................................................................................................................................................... 38

   Defining Functions................................................................................................................................................................. 39

       Exercise 1 .......................................................................................................................................... 41

       Exercise 2 .......................................................................................................................................... 41

       Exercise 3 .......................................................................................................................................... 42

   Documentation ........................................................................................................................................................................ 43

       Using doc .......................................................................................................................................... 43

       find-doc ............................................................................................................................................. 43

       Documenting a function ................................................................................................................... 44

       Clojure API ........................................................................................................................................ 44

CLOJURE AND JAVA................................................................................................................................... 45

   Working with Java ................................................................................................................................................................. 45

@ 2010 by Satish Talim                                                                                                                                                             Page 5
Prepared exclusively for Clojure 101 Course participants


       Importing multiple classes ................................................................................................................ 45

       Create a Java object .......................................................................................................................... 45

       Accessing methods ........................................................................................................................... 46

       ..chains .............................................................................................................................................. 46

       doto .................................................................................................................................................. 47

       Accessing static fields........................................................................................................................ 47

       Accessing static methods .................................................................................................................. 47

       -> macro ............................................................................................................................................ 47

       Exception handling............................................................................................................................ 48

       Some More Examples ....................................................................................................................... 49

       Source for a function......................................................................................................................... 49

       Inspector ........................................................................................................................................... 49

DIVING INTO CLOJURE .............................................................................................................................. 51

   Namespaces .............................................................................................................................................................................. 51

       in-ns function .................................................................................................................................... 51

       ns ...................................................................................................................................................... 51

   More on Bindings ................................................................................................................................................................... 53

       let ...................................................................................................................................................... 53

       binding .............................................................................................................................................. 54

   Echo Server ............................................................................................................................................................................... 55

       Port ................................................................................................................................................... 55

       Socket ............................................................................................................................................... 56

       clojure-contrib library ....................................................................................................................... 56

       server-socket API .............................................................................................................................. 56

       duck-streams API .............................................................................................................................. 57

@ 2010 by Satish Talim                                                                                                                                                              Page 6
Prepared exclusively for Clojure 101 Course participants


       Step 1: Define a namespace .............................................................................................................. 57

       Step 2: Define a port ......................................................................................................................... 58

       Step 3: Define a function................................................................................................................... 58

       Step 4: Start the server ..................................................................................................................... 58

       Step 5: Test the Echo Server ............................................................................................................. 59

   StructMaps ................................................................................................................................................................................ 59

   Refs................................................................................................................................................................................................ 61

   Transactions ............................................................................................................................................................................. 61

       A Simple Accounts example .............................................................................................................. 63

   Compiling using Clojure Box .......................................................................................................................................... 64

About the Author ...................................................................................................................................... 67




@ 2010 by Satish Talim                                                                                                                                                                      Page 7
Prepared exclusively for Clojure 101 Course participants



Acknowledgements

My interest in Clojure was aroused when Michael Kohl organized the first-ever, free, four-
week, online Clojure course on RubyLearning.org –
http://rubylearning.com/blog/2010/03/09/clojure-101-a-new-course/
(for people with some background in Lisp and / or Clojure.)

Having had no previous exposure to Lisp and Clojure, I could not keep up with the others in
the course after the first week. I decided to start making these study notes from the
perspective of a beginner in Lisp and Clojure but with some experience in other programming
languages.

There are a good number of people who deserve thanks for their help and support they
provided, either before or while this eBook is being written, and there are still others whose
help will come after the eBook is released.

I would specially like to thank Baishampayan Ghose, Daniel Solano Gomez and Michael Kohl
for offering suggestions and proofreading these study notes.

The material in these study notes is drawn primarily from the references mentioned below.
My acknowledgment and thanks to all of them.

Clojure Home
http://clojure.org/

Clojure - Functional Programming for the JVM by R. Mark Volkmann –
http://java.ociweb.com/mark/clojure/article.html

Programming Clojure by Stuart Halloway –
http://www.pragprog.com/titles/shcloj/programming-clojure

The Joy of Clojure by Michael Fogus and Chris Houser –
http://www.manning.com/fogus/

Clojure in Action by Amit Rathore –
http://www.manning.com/rathore/

Practical Clojure by Luke Van der Hart –
http://apress.com/book/view/1430272317

Clojure Programming/Concepts –
http://en.wikibooks.org/wiki/Clojure_Programming/Concepts


@ 2010 by Satish Talim                                                                 Page 8
Prepared exclusively for Clojure 101 Course participants


Functional Programming with Clojure Screencast by PeepCode –
http://peepcode.com/products/functional-programming-with-clojure




@ 2010 by Satish Talim                                             Page 9
Prepared exclusively for Clojure 101 Course participants



ABOUT THE EBOOK


Assumptions


        These study notes are for absolute beginners in Clojure.
        Some previous programming background is essential.
        Some parts require knowledge of Java.
        The programs in these study notes have been tested using the Clojure 1.1 version.
        Since I have a Windows box, I have mentioned the installation of Clojure and other
        dependencies for MS Windows only.



Concept and Approach


I have tried to organize this eBook in which each chapter builds upon the skills acquired in the
previous chapter, so that you will never be called upon to do something that you have not
already learned. This eBook not only teaches you how to do something, but also provides you
with the chance to put those morsels of knowledge into practice with exercises. I have
therefore included several exercises, or assignments, in this eBook so that you will have
opportunities to apply your knowledge.



How to Use This Clojure eBook


I recommend that you go through the entire Clojure eBook chapter by chapter, reading the
text, running the sample programs and doing the assignments along the way. There are no
large applications in this book – just small, self-contained sample programs. This will give you
a much broader understanding of how things are done (and of how you can get things done),
and it will reduce the chance of anxiety, confusion, and worse yet, mistakes.

It is best to read this eBook and complete its assignments when you are relaxed and have time
to spare. Nothing makes things go wrong more than working in a rush. And keep in mind that
Clojure and the assignments in this eBook are fun, not just work exercises. So go ahead and
enjoy it.




@ 2010 by Satish Talim                                                                  Page 10
Prepared exclusively for Clojure 101 Course participants


About the Conventions Used in This Clojure eBook


Explanatory notes (generally provides some hints or gives a more in-depth explanation of
some point mentioned in the text) are shown shaded like this:

This is an explanatory note. You can skip it if you like - but if you do so, you may miss
something of interest!

Any source code in this Clojure eBook, is written like this:

(defn greet
  ([] (greet " world"))
  ([name] (str "Hello " name)))

When there is a sample program to accompany the code, the program name is shown like this:
program.clj

Though we would be discussing Clojure 1.1 on the Windows platform, these notes are
appropriate for Linux/Mac users as well.

If you notice any errors or typos, or have any comments or suggestions or good exercises I
could include, please email me at satish.talim@gmail.com.



Learn Clojure Online and for Free


If you want to learn            Clojure    Programming     for   free,   do   join   the   batch   at
http://rubylearning.org/

RubyLearning is the first and only site in the world that teaches Ruby and Clojure
Programming for free. Over 30 mentors help you through the learning process – 24x7.




@ 2010 by Satish Talim                                                                       Page 11
Prepared exclusively for Clojure 101 Course participants



INTRODUCTION TO CLOJURE


What is Clojure?


Clojure is a dynamically-typed, functional programming language that runs on the JVM (Java 5
or greater) and provides interoperability with Java.
http://en.wikipedia.org/wiki/Functional_programming

"A key characteristic of Clojure is that it is a functional language, which means that functions
are the fundamental building-block for programs rather than instructions, as is the case in
most other programming languages (known as imperative languages). In Clojure, functions are
best thought of as more like their counterparts in mathematics – a function is simply an
operation that takes a number of parameters (also called arguments), and returns a value.
These functions always return the same result when passed the same arguments. Imperative
languages perform complex tasks by executing large numbers of instructions, which
sequentially modify a program state until a desired result is achieved. Functional languages
achieve the same goal through nested function composition – passing the result of one
function as a parameter to the next. By composing and chaining function calls, along with
recursion (a function calling itself), a functional program can express any possible task that a
computer is capable of performing. An entire program can itself be viewed as a single
function, defined in terms of smaller functions. The nesting structure determines the
computational flow, and all the data is handled through function parameters and return
values." - From Practical Clojure.

A major goal of Clojure is managing concurrency. Wikipedia has a great definition of
concurrency: "Concurrency is a property of systems in which several computations are
executing and overlapping in time, and potentially interacting with each other. The
overlapping computations may be executing on multiple cores in the same chip, preemptively
time-shared threads on the same processor, or executed on physically separated processors."
The primary challenge of concurrency is managing access to a shared, mutable state.

Clojure helps you write correct concurrent programs by emphasizing immutability. Clojure
enforces isolating changes in mutable state as either atomic operation with atoms, within a
transaction with refs, or asynchronously with agents. Additionally, there are no explicit locks
in Clojure, so this common source of deadlock is removed.

Michael Fogus, author of the book "The Joy of Clojure" says that - "Clojure was born out of
creator Rich Hickey's desire to avoid many of the complications, both inherent and incidental,
of developing concurrent applications using Java and C++. The Java Virtual Machine is an
amazingly practical platform -- it is mature, fast, and widely deployed. It supports a variety
of hardware and operating systems and has a staggering number of libraries and support tools


@ 2010 by Satish Talim                                                                  Page 12
Prepared exclusively for Clojure 101 Course participants


available, all of which Clojure can take advantage of, thus allowing prospective developers to
avoid the costs of maintaining yet another infrastructure while leveraging existing libraries."

The following shows briefly the release dates for various versions of Clojure:

        1.2 is expected soon.
        1.1 (the current version) released in Dec. 2009.
        1.0 released in May 2009.
        Clojure was first released on October 16, 2007.




@ 2010 by Satish Talim                                                                 Page 13
Prepared exclusively for Clojure 101 Course participants




GETTING STARTED


Labrepl Download and Installation (for MS Windows)


What's Labrepl?


Labrepl is an environment for exploring the Clojure language. It includes:

        a web application that presents a set of lab exercises with step-by-step instructions
        an interactive repl for working with the lab exercises
        up-to-date versions of Clojure, contrib, incanter, compojure and a bunch of other
        libraries to explore

The Labrepl site mentions how one can use Labrepl on other operating systems.
http://github.com/relevance/labrepl


Downloading and Installing Labrepl (for MS Windows)


        Download and install Java version 6 - this is a pre-requisite.
        http://java.sun.com/javase/downloads/index.jsp

        Next, go to the Labrepl site and click on the "Download Source" button on the top of
        the page. A .zip file will get downloaded to your computer. Extract this .zip file to
        your c: drive. On my computer it created a folder c:relevance-labrepl-d6b9759.

        For Labrepl to work we shall also need Leiningen.
        http://github.com/technomancy/leiningen

        Leiningen is a build tool for Clojure. Installation of Leiningen on MS Windows is
        complicated, because automatic install isn't implemented yet. For MS Windows you
        need to download lein.bat script, and put it into the folder c:leiningen.
        http://github.com/technomancy/leiningen/raw/stable/bin/lein.bat

        Set your system environment variable "PATH" to include the folder c:leiningen.

        Create a sub-folder c:leiningenlib.

@ 2010 by Satish Talim                                                                Page 14
Prepared exclusively for Clojure 101 Course participants




        Next download        leiningen-1.1.0-standalone.jar   and   copy   it   to   the    folder
        c:leiningenlib.
        http://github.com/downloads/technomancy/leiningen/leiningen-1.1.0-
        standalone.jar

        After this, download the clojure.jar package. A .zip file gets downloaded to your
        computer. From this .zip file extract clojure.jar and copy it to the c:leiningenlib
        folder.
        http://code.google.com/p/clojure/downloads/list

        Edit lines 14 and 15 of lein.bat to correct the path, namely:
            o set LEIN_JAR=c:leiningenlibleiningen-1.1.0-standalone.jar
            o set CLOJURE_JAR=c:leiningenlibclojure.jar

        Open a new command window and change folder to c:relevance-labrepl-d6b9759.
        Next type lein deps to install all the dependent libraries. This might take some time.

        Close the command window.


Starting the REPL

Interaction with Clojure is often performed at the REPL (Clojure read-eval-print loop). To
start a REPL, open a new command window and change folder to c:relevance-labrepl-
d6b9759. Next type:

c:relevance-labrepl-d6b9759> scriptrepl



This starts a new REPL session and you are presented with a simple user> prompt. It is at this
point that REPL waits for user input. The user namespace is the REPL default, like the default
package in Java. You should treat user as a scratch namespace for exploratory development.
After user> type (println "Hello World") and press ENTER, as follows:

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




@ 2010 by Satish Talim                                                                     Page 15
Prepared exclusively for Clojure 101 Course participants


The second line above, Hello World, is the console output you requested. The third line, nil,
is the return value of the call to Clojure's println (the funtion used to display something on
the screen).

For a list of all the functions available in the clojure.core API, see –
http://richhickey.github.com/clojure/clojure.core-api.html.


If you get your REPL into a state that confuses you, the simplest fix is to close the command
window.


Loading a file in the REPL

If you have a block of code that is too large to conveniently type at the REPL, save the code
into a file, and then load that file from the REPL. You can use an absolute path or a path
relative to where you launched the REPL.

Here's how you would load a file in your REPL:

(load-file file-name)



The load-file function sequentially reads and evaluates the set of forms (more on this later)
contained in the file.

A Clojure program is stored in a text file with the extension .clj. Let us load the file test.clj
located in the folder c:userstalimmyprojectsrctest:

(load-file    "c:/users/talim/myproject/src/test/test.clj") ; => nil



Clojure Box Download and Installation (for MS Windows)


Note: If you have installed Labrepl then you can ignore this step.


1. Download and install Java version 6 - this is a pre-requisite.
    http://java.sun.com/javase/downloads/index.jsp

2. Download and install "Clojure Box". Clojure Box is an all-in-one installer for Clojure on
   Windows. You simply install and run this one thing, and you get a REPL (Clojure read-eval-
   print loop) and all the syntax highlighting and editing goodies from clojure-mode and
   Slime, plus all the power of Emacs under the hood.
    http://clojure.bighugh.com/


@ 2010 by Satish Talim                                                                   Page 16
Prepared exclusively for Clojure 101 Course participants


Note:

        You can watch a video of "Install Clojure - ClojureBox".
        http://vimeo.com/9219062

        Read the post install notes - http://bitbucket.org/shoover/clojure-box/src/tip/post-
        install.txt.


Test if Clojure Box works

Interaction with Clojure is often performed at the REPL.

To test whether Clojure works, double-click on the "Clojure Box" icon on your desktop. This
starts a new REPL session and you are presented with a simple user> prompt. It is at this
point that REPL waits for user input. The user namespace is the REPL default, like the default
package in Java. You should treat user as a scratch namespace for exploratory development.

After user> type (println "Hello World") and press ENTER:

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



The second line above, Hello World, is the console output you requested. The third line, nil,
is the return value of the call to Clojure's println (the funtion used to display something on
the screen).

For a list of all the functions available in the clojure.core API, see –
http://richhickey.github.com/clojure/clojure.core-api.html.


If you get your REPL into a state that confuses you, the simplest fix is to kill the REPL with
Ctrl-C.


Loading a file in Clojure Box

If you have a block of code that is too large to conveniently type at the REPL, save the code
into a file, and then load that file from the REPL. You can use an absolute path or a path
relative to where you launched the REPL.

Here's how you would load a file in your REPL:



@ 2010 by Satish Talim                                                                Page 17
Prepared exclusively for Clojure 101 Course participants



(load-file file-name)



The load-file function sequentially reads and evaluates the set of forms (more on this later)
contained in the file.

A Clojure program is stored in a text file with the extension .clj. Let us load the file test.clj
located in the folder c:userstalimmyprojectsrctest:

(load-file    "c:/users/talim/myproject/src/test/test.clj") ; => nil



NetBeans/Enclojure Download and Installation (for MS Windows)

Note: If you have installed Labrepl or Clojure Box then you can ignore this step.

    1. Download and install Java version 6 - this is a pre-requisite.
        http://java.sun.com/javase/downloads/index.jsp

    2. Download and install NetBeans 6.8 (Java SE option).
        http://netbeans.org/downloads/index.html

    3. Download the latest Enclojure .nbm file.
        http://github.com/EricThorsen/enclojure/downloads

        In NetBeans go to Tools > Plugins. In the dialog click on Downloaded then click the
        "Add Plugins..." button.

        Navigate to the location where you saved the NBM file, select it and click the "Open"
        button.

        Highlight "Clojure Plugin" and click the "Install" button.

        Restart the NetBeans IDE.

        Next, navigate to Tools > Options > Clojure and at the bottom of the screen select
        clojure-1.1.0 for the Clojure platform. Click the "OK" button.

        Restart the NetBeans IDE.




@ 2010 by Satish Talim                                                                   Page 18
Prepared exclusively for Clojure 101 Course participants


To create a Clojure Project in NetBeans

    1. Navigate to File > New Project... Select Categories Clojure and click the "Next"
       button.

    2. I created a folder c:ClojureProjects on my hard disk.

    3. I typed the following:
             Project Name: RL
             Default namespace: com.rl.hello
             Project location: c:ClojureProjects

    4. Click the "Finish" button.


To start the REPL in NetBeans

    1. Right click on the newly created project namely RL, which you should be seeing in the
       Projects window.

    2. Select "Start Project REPL" in the window that pops up.


Anatomy of the Enclojure REPL Panel

See: http://www.enclojure.org/Anatomy+of+the+Enclojure+Repl+Panel

Note: You can watch a video of "Install Clojure - NetBeans".
http://vimeo.com/9220148



Syntax

Clojure is a Lisp dialect and has a syntax that uses parentheses and prefix notation. For
example, in Java one might write foo(a, b, c), whereas in a Lisp dialect this becomes (foo a,
b, c). Since the commas are whitespace and Clojure ignores them, it can be simplified further
to (foo a b c). Many text editors and IDEs highlight matching parentheses, so it isn't necessary
to count them in order to ensure they are balanced.

Clojure is case-sensitive.


Comments

Open a new REPL and try out whatever we discuss, from now on.

@ 2010 by Satish Talim                                                                  Page 19
Prepared exclusively for Clojure 101 Course participants



There are two ways in which you can comment in Clojure.

A line comment is:

; This is a single line Clojure comment



For block comments:

(comment text)



It should be noted that the block comment form above does have a return value, namely nil.
So you can't just "comment out" a piece of your code with it, because it still leaves a trace.
This form is sometimes used at the end of a source code file to demonstrate usage of an API.

For example, the Clojure inspector library ends with the following comment, demonstrating
the use of the inspector:

(comment
(load-file    "src/inspector.clj" )
(refer   'inspector)
(inspect-tree     {:a    1    :b   2   :c    [1    2    3   {:d   4    :e   5   :f   [6   7   8]}]})
(inspect-table     [[1    2    3][4    5    6][7    8    9][10    11    12]])
)



Clojure Coding Guidelines & Naming Convention

    1. Use two spaces for indentation.

    2. Make your names for functions, vars as descriptive as possible, without being overly
       verbose.

    3. Use lower-case letters for names.

    4. The names of predicate functions (returning a truthy (everything not nil or false) or
       falsy (false and nil) should typically end with a question mark (?).

    5. End the name of a function in an exclamation mark (!) if it is destructive.

The obvious exceptions to the guidelines above are when generating Java code, which
requires that Java naming conventions be observed.



@ 2010 by Satish Talim                                                                                 Page 20
Prepared exclusively for Clojure 101 Course participants


For more details please see the Clojure Library Coding Standards.
http://www.assembla.com/wiki/show/clojure/Clojure_Library_Coding_Standards


The naming convention in Clojure is to use all lowercase with hyphens separating words in
multi-word names, unlike the Java convention of using camelcase.

An example:

(function-name arg1 arg2 arg3)



Forms

Clojure code is composed of Clojure data. When you run a Clojure program, a part of Clojure
called the reader reads the text of the program in chunks called forms and translates them
into Clojure data structures. Clojure then compiles and executes the data structures.

A Clojure form is basically just an expression. It's any piece of code that evaluates down to a
single value.

The Clojure forms are: symbols, literals (i.e. booleans, nil, numbers, characters, strings,
keywords), lists, vectors, maps and sets.


Symbols

Symbols are used to name things. Symbols name all sorts of things in Clojure:
      Functions like str and concat

        Clojure does not have operators. Characters like + - * / are just functions

        Java classes like java.lang.String and java.util.Random

        Namespaces like clojure.core and Java packages like java.lang

        Data structures and references.

Symbols cannot start with a number and can consist of alphanumeric characters, plus +, -, *,
/, !, ?, ., and _.

You can call a function through a symbol such as println:

(println "Hello Clojure participants") ; => Hello Clojure participants




@ 2010 by Satish Talim                                                                 Page 21
Prepared exclusively for Clojure 101 Course participants


Rather than calling a function through a symbol, you might choose just to retrieve the
function itself. The literal representation of a function at the REPL is just a mangled name:


println



Sometimes you want to refer to the symbol itself, without retrieving whatever it refers to. To
do this, you can quote the symbol:

(quote println) ; => println



Quoting is so common that that there is a sugared form: simply put a single quote in front of
any symbol to prevent that form from being evaluated:

'println ; => println



Vars and Bindings

The special form (these are forms evaluated in a special way) def creates a var. If the var did
not already exist and no initial value is supplied, the var is unbound. In the code below, x is a
symbol which is used to identify the var in the future. At this point, x has no "value", and so
we can't refer to it:

(def x) ; => #'user/x
x ; => java.lang.IllegalStateException: var user/x is unbound.



If called with an additional parameter it creates a root binding or rebinds the var in case it
was already bound. This binding is like an "invisible" link between the var and the value. For
example, the following def creates a var named user/my-var in the namespace user:

(def my-var 10) ; => #'user/my-var



The symbol user/my-var refers to a var that is bound to the value 10. The initial value of a
var is called its root binding.

Clojure provides bindings which are like constants in other languages, which are not intended
to be changed after a value is assigned. Other threads can then override that binding
temporarily. Threads which do not have a thread local binding will inherit the root binding.
There are global bindings, thread-local bindings, bindings that are local to a function and
bindings that are local to a given form.



@ 2010 by Satish Talim                                                                   Page 22
Prepared exclusively for Clojure 101 Course participants


The def special form creates a global binding and optionally gives it a "root value" that is
visible in all threads unless a thread-local value is assigned.

In Clojure, the object that your var is referring to can't change. If you want your var to refer
to a different value, you have to rebind it to a new object, a new value. Although vars can be
rebound, it is generally not done in a program except to create thread-local bindings.


Literals


Booleans and nil

Clojure’s rules for booleans (true and false) are easy to understand:

    1. true is true, and false is false.

    2. In addition to false, nil (meaning 'nothing/no-value'- represents Java null) also
       evaluates to false when used in a boolean context.

    3. Other than false and nil, everything else evaluates to true in a boolean context.


Numbers

A number consists of only the digits 0-9, a decimal point '.', a sign ('+' or '-'), and an optional 'e'
for numbers written in exponential notation. In addition to these elements, numbers in
Clojure can take either octal or hexadecimal form and also include an optional 'M' (this is used
to explicitly create a BigDecimal).

Clojure supports the following numeric types: integer, floating point, ratio.

Integers comprise the whole number set, both positive and negative. That is, any number
starting with an optional sign or digit followed exclusively by digits is considered and stored
as an integer. Integers in Clojure can theoretically take an infinitely large value, although in
practice the size is limited by the memory available.




@ 2010 by Satish Talim                                                                        Page 23
Prepared exclusively for Clojure 101 Course participants


Floating point numbers are of the form of some number of digits, a decimal point, followed
by some number of digits. However, floating point numbers can also take an exponential form
where a significant part is followed by an exponent part separated by a lower or uppercase
'E'.

0x7F ; => hexadecimal number whose value is 127
0177 ; => octal number whose value is 127
11.7e-3 ; => 0.0117
(+ 1 2 3 4) ; => 10
(/ 22 7) ; => 22/7
200/5 ; => 40



In the code above, we first use the + function to add the numbers 1, 2, 3 and 4. The result of
(/ 22 7) is surprising as Clojure has a built in clojure.lang.Ratio type. Using ratios help avoid
inaccuracies in long computations. Ratios are represented by an integer numerator and
denominator. Also observe that the ratio 200 / 5 will resolve to the integer 40.

Lets first try a computation of (1/5 * 5/1) as floating point. Later we try the same with Ratio.

(def x (/ 1.0 5.0))
(def y (/ 5.0 1.0))
(* x y) ; => 1.0
(def p (* x x x x x x x x x x))
(def q (* y y y y y y y y y y))
(* p q) ; => 1.0000000000000004



The value of (* p q) above is 1.0000000000000004 instead of 1 which is what we want. This is
due to the inaccuracies of x and y multiplying as we create p and q. You really don't want
such calculations happening in your financial transactions!

The same done with ratios below:

(def x (/ 1 5))
(def y (/ 5 1))
(* x y) ; => 1
(def p (* x x x x x x x x x x))
(def q (* y y y y y y y y y y))
(* p q) ; => 1



Using a floating point literal instead, we get:

(/ 22.0 7) ; => 3.142857142857143



@ 2010 by Satish Talim                                                                   Page 24
Prepared exclusively for Clojure 101 Course participants


Arbitrary-precision arithmetic

In Clojure, we can do arbitrary-precision arithmetic - a technique whereby calculations are
performed on numbers whose digits of precision are limited only by the available memory of
the host system. Clojure relies on Java's BigDecimal class for arbitrary-precision decimal
numbers and on Java's BigInteger class for arbitrary-precision integers.
http://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic


If you are doing arbitrary-precision math, append M to a number to create a BigDecimal
literal:

(+   1   (/    0.00001     1000000000000000000)) ; => 1.0
(+   1   (/    0.00001M       1000000000000000000)) ; => 1.00000000000000000000001M



Clojure objects are Java objects and you can use Java's Reflection API methods such as class,
ancestors, and instance? to reflect against the underlying Java object model.

(class (+      1   (/    0.00001M    1000000000000000000))) ; => java.math.BigDecimal



Clojure's approach to arbitrary-sized integers is simple: just don't worry about it. Clojure will
automatically upgrade to Long or BigInteger when you need it. Try creating some small and
large integers, and then inspect their class:

(class    (*    100     100    100)) ; => java.lang.Integer
(class    (*    9000     9000    9000)) ; => java.lang.Long
(class    (*    9000     9000    9000   9000   9000   9000   9000   9000)) ; => java.math.BigInteger



format

Round off a number to say 2 decimal places:

(format "%.2f" 1.2345) ; => "1.23"



Characters and Strings

Clojure character literals are preceded by a backslash. Their literal syntax is {letter}, where
letter can be a letter or the name of a character: backspace, form-feed, newline, return,
space, or tab. These yield the corresponding characters.

Clojure strings are Java strings. They are immutable, and have access to all the underlying
Java methods. They are delimited by double quotes ("), and they can span multiple lines.


@ 2010 by Satish Talim                                                                       Page 25
Prepared exclusively for Clojure 101 Course participants


Strings are sequences of characters. The function concat returns a list of character literals, of
the elements in the supplied strings:

(concat "Hello" " World")       ; => (H e l l o space W o r l d)



Clojure's str is a function call that concatenates an arbitrary list of arguments into a string:

(str   h    e   l   l o space   w   o   r   l    d) ; => "hello world"
(str "Hello" " " "World") ; => "Hello World"



Standard Java escape characters are supported. If you want to put a double quote inside a
string then you have to escape the double quote. The backslash is the escape character:

(println "She replied: "Hello" to my greetings.")
; => She replied: "Hello" to my greetings.



Keywords

A keyword is like a symbol, except that keywords begin with a colon (:). Keywords resolve to
themselves:

:foo ; => :foo


The fact that keywords resolve to themselves makes keywords useful as keys.


Exercises


Exercise 1

Write a Clojure program that displays how old I am, if I am 979000000 seconds old.

Sample solution:

(println "You are" (/ 979000000 60.0 60 24 365) "years old")
; => You are 31.04388635210553 years old
; Note that println automatically added a space between its arguments


We can improve upon the above program. It's always better to perform the calculation using
exact numbers and then coerce the result if needed (we use float in the example below). This
is an advantage which Clojure offers when compared to other languages; you can perform


@ 2010 by Satish Talim                                                                     Page 26
Prepared exclusively for Clojure 101 Course participants


calculations with exact numbers instead of floating point approximations. A better solution
would be:

(println "You are" (float (/ 979000000 60 60 24 365)) "years old")
; => You are 31.043886 years old



Exercise 2

Write a Clojure program that tells you how many minutes there are in a year (do not bother
right now about leap years etc.).

Sample solution:

(println "There are" (* 60 24 365) "minutes in a year")
; => There are 525600 minutes in a year




@ 2010 by Satish Talim                                                             Page 27
Prepared exclusively for Clojure 101 Course participants




CHARGING AHEAD

A Quick look at Collections

Clojure provides the collection types list, vector, set and map. The Clojure collection types
are immutable, heterogeneous and persistent. By immutable it means that their contents
cannot be changed. By heterogeneous it means that they can hold any kind of object. By
persistent it means that when a new version of a collection is created by adding or removing
something from it, the new version shares structure with the old one. The old version will be
accessible only when we hold a reference to its head otherwise it will be garbage collected.


Lists

Lists are written with parenthesis. Lists are the traditional lisp singly linked lists. Lists can
contain items of any type, including other collections:

; Empty list
() ; => ()
(class ()) ; => clojure.lang.PersistentList$EmptyList
'(a b c) ; => (a b c)
(class '(a b c)) ; => clojure.lang.PersistentList



A list is "just data," but it is also used to call functions. They are ideal when new items will be
added to or removed from the front. Lists are not efficient for finding items by index.

An example of a list whose first item names a Clojure function:

(+   1   2)



In Clojure, data and code have the same representation. (a b c) is a call to a function named
a with arguments b and c. To make this data instead of code, the list needs to be quoted. '(a
b c) or (quote (a b c)) is a list of the values a, b and c.

It may be good to note that lists are singly linked lists.




@ 2010 by Satish Talim                                                                     Page 28
Prepared exclusively for Clojure 101 Course participants


Vectors

Vectors are essentially like dynamically-sized arrays. Vectors store a series of values like lists
do and can be used like lists, except that they can be indexed by integers. Vectors are
written with square brackets:

[1 2 3] ; => [1 2 3]
(class [1 2 3]) ; => clojure.lang.PersistentVector
[ ] ; => [ ]
(class [ ]) ; => clojure.lang.PersistentVector



Vectors are ideal when new items will be added to or removed from the back. Vectors are
efficient for finding or changing items by index i.e. vectors are functions of their indices:

; retrieve an element by its index
(["hello" "world" 1 2 3] 1) ; => "world"



Note: Unless the list characteristic of being more efficient at adding to or removing from the
front is significant for a given use, vectors are typically preferred over lists. This is mainly due
to the vector syntax of [...] being a bit more appealing than the list syntax of '(...). It doesn't
have the possibility of being confused with a call to a function, macro or special form.


Sets

Sets are collections of unique items. Sets are zero or more forms enclosed in braces preceded
by #. The #{} reader macro is only for hash sets:

#{ } ; => #{ }
(class #{ }) ; => clojure.lang.PersistentHashSet
#{:a :b :c} ; => #{:a :b :c}



Sets are preferred over lists and vectors when duplicates are not allowed and items do not
need to be maintained in the order in which they were added. Clojure supports two kinds of
sets, unsorted and sorted. Hash sets are generally preferred over sorted sets as they are much
faster. Sorted sets are important when keeping things sorted is very important. Here are some
more ways to create a set:

(sorted-set "Mandy" "Anita" "Rich") ; #{"Anita" "Mandy" "Rich"}
(hash-set "Mandy" "Anita" "Rich") ; #{"Anita" "Mandy" "Rich"}
; duplicates are removed
(hash-set "Rich" "Mandy" "Anita" "Rich") ; #{"Anita" "Mandy" "Rich"}



@ 2010 by Satish Talim                                                                      Page 29
Prepared exclusively for Clojure 101 Course participants


Maps

Maps are zero or more key/value pairs where both can be any kind of object and enclosed in
braces. Maps store unique keys and one value per key. Often keywords are used for map keys:

{ } ; => { }
(class { }) ; => clojure.lang.PersistentArrayMap
{:Ruby   "Matz"    :Clojure    "Hickey"} ; => {:Ruby       "Matz"   :Clojure   "Hickey"}



You can use a map directly, it is not necessary to bind it to a name:

(:a {:a 1, :b 2}) ; => 1



We can use def to save the map into a Clojure var:

(def   inventors    {:Ruby    "Matz"    :Clojure    "Hickey"})



Commas are considered whitespace, and can be used to organize the pairs:

(def   inventors    {:Ruby    "Matz",    :Clojure    "Hickey"})



Maps are functions. If you pass a key to a map, it will return that key’s value, or it will return
nil if the key is not found:

(:Clojure inventors) ; => Hickey
(inventors :Java) ; => nil



The keys function returns a sequence of the map's keys:

; Usage: (keys map)
(keys inventors) ; => (:Ruby :Clojure)



The vals function returns a sequence of the map's values:

; Usage: (vals map)
(vals inventors) ; => ("Matz" "Hickey")




@ 2010 by Satish Talim                                                                     Page 30
Prepared exclusively for Clojure 101 Course participants


Some functions on collections

There are many core functions that operate on all kinds of collections; far too many to
describe here. A small subset of them is described next, mostly using vectors and sometimes
lists.


count function

The count function returns the number of items in any collection.

(count [22 "green" false]) ; => 3
; empty collections correctly return 0
(count '()) ; => 0



reverse function

The reverse function returns a sequence of the items in the collection in reverse order.

(reverse [2 42 72]) ; => (72 42 2)
(reverse '(2 42 72)) ; => (72 42 2)
; strings are collections too
(reverse "hello") ; => (o l l e h)



apply function

The apply function returns the result of a given function when all the items in a given
collection are used as arguments.

(apply - [34 23 9])      ; => 2



map function

(map f coll)



map takes a source collection coll and a function f, and it returns a new sequence by invoking
f on each element in the coll.

(map * [1 2 3 4] [1 2 3 4]) ; => (1 4 9 16)




@ 2010 by Satish Talim                                                                 Page 31
Prepared exclusively for Clojure 101 Course participants


Sequences

A sequential collection is one that holds a series of values without reordering them.

A sequence is a sequential collection that represents a series of values that may or may not
exist yet. They may be values from a concrete collection, or values that are computed as
necessary. A sequence may be empty.

Sequences include Java collections, Clojure-specific collections, strings, streams, directory
structures and XML trees. Because so many things are sequences, the sequence library is very
powerful. Remember that the sequence library can be used with all collections (lists, vectors,
sets, maps ...).

Important: Most Clojure sequences are lazy: they generate elements only when they are
actually needed. Clojure sequences are immutable: they never change.


seq

The seq function turns any core collections into something called a seq i.e. the seq function
will return a seq on any seq-able collection (coll):

(seq coll)


seq will return nil if its coll is empty or nil.

An example:

(seq [1 2 3]) ; => (1 2 3)
(seq [ ]) ; => nil



first

You can get the first item in a sequence:

(first   aseq)



first returns nil if its argument is empty or nil.




@ 2010 by Satish Talim                                                                  Page 32
Prepared exclusively for Clojure 101 Course participants


An example:

(first [34 23 15]) ; => 34
(first [ ]) ; => nil



rest

You can get everything after the first item, in other words, the rest of a sequence:

(rest   aseq)



rest returns an empty seq (not nil) if there are no more items.

An example:

(rest [34 23 15]) ; => (23 15)
(rest [ ]) ; => ()
(class (rest [ ])) ; => clojure.lang.PersistentList$EmptyList



cons

You can construct a new sequence by adding an item to the front of an existing sequence:

(cons   elem    aseq)



An example:

(cons 1 [2 3 4]) ; => (1 2 3 4)



Under the hood, first, rest and cons are declared in a Java interface clojure.lang.ISeq.


next

The next function will return the seq of items after the first:

(next   aseq)



(next aseq) is equivalent to (seq (rest aseq)).



@ 2010 by Satish Talim                                                                 Page 33
Prepared exclusively for Clojure 101 Course participants


An example:

(next [1 2 3 4]) ; => (2 3 4)



conj, into

(conj    coll      element      &    elements)
(into    to-coll        from-coll)



conj adds one or more elements to a collection, and into adds all the items in one collection
to another. For lists, conj and into add to the front:

(conj    '(10      20    30)    :a) ; => (:a 10 20 30)
(into    '(10      20    30)    '(:a    :b   :c)) ; => (:c :b :a 10 20 30)



For vectors, conj and into add elements to the back:

(conj    [10      20    30]    :a) ; => [10 20 30 :a]
(into    [10      20    30]    [:a    :b   :c]) ; => [10 20 30 :a :b :c]



range

range produces a sequence from a start to an end, incrementing by step each time. Ranges
include their start, but not their end. If you do not specify them, start defaults to zero, and
step defaults to 1.

(range    10      20    2) ; => (10 12 14 16 18)



repeat

The repeat function repeats an element p n times:

(repeat      5    "p") ; => ("p" "p" "p" "p" "p")



iterate, take

(iterate      f    x)



iterate begins with a value x and continues forever, applying a function f to each value to
calculate the next.
@ 2010 by Satish Talim                                                                 Page 34
Prepared exclusively for Clojure 101 Course participants



If you begin with 1 and iterate with inc, you can generate the whole numbers:

(take    10   (iterate    inc   1)) ; => (1 2 3 4 5 6 7 8 9 10)



Since the sequence is infinite, you need another new function to help you view the sequence
from the REPL.

(take    n    sequence)



take returns a lazy sequence of the first n items from a collection and provides one way to
create a finite view onto an infinite collection.

The following example creates a lazy seq of all natural numbers:

<pre class="brush: clojure">


An usage example:

(take 5 natural-numbers) ; => (0 1 2 3 4)



concat

The concat function can be used for plain concatenation of any collection:

(concat [22 "green" false] [33 44]) ; => (22 "green" false 33 44)
; the two collections can be of different types
(concat #{22 "green" false} '(33 44)) ; => ("green" false 22 33 44)




Flow Control
@ 2010 by Satish Talim                                                             Page 35
Prepared exclusively for Clojure 101 Course participants




if, if-not

Clojure’s if evaluates its first argument. If the argument is logically true, it returns the result
of evaluating its second argument. If you want to define a result for the "else" part of if, add
it as a third argument (but this is optional):

(println (if      (<   34   100)   "yes" ))
; => yes
(println (if 0 "Zero        is   true"   "Zero   is   false")) ; => Zero   is   true



If the first argument to if is logically false and you didn't specify an else form, it returns nil:

(if   (<     50000   100)   "yes" )
; => nil



The if-not macro does the inverse of what the if special form does. The general structure of
this macro is:

(if-not test consequent alternative?)



Here, if the test is false, the consequent is evaluated, else if it is true and the alternative is
provided, it is evaluated instead.


cond, condp
cond is like the case statement of Clojure. The general form looks like the following:

(cond & clauses)




Here's an example:


@ 2010 by Satish Talim                                                                       Page 36
Prepared exclusively for Clojure 101 Course participants



(def x 10)
(cond
(< x 0) (println "Negative!")
(= x 0) (println "Zero!"))
; => nil
(cond
(< x 0) (println "Negative!")
(= x 0) (println "Zero!")
:default (println "Positive!"))
; => Positive!



As you can see, the clauses are a pair of expressions, each of the form test consequent. Each
test expression is evaluated in sequence, and when one returns true, the associated
consequent is evaluated and returned. If none return true, nil is returned. If a :default is
provided, the associated consequent is evaluated and returned instead.

The general form of condp looks like the following:

(condp pred expr & clauses)



The condp macro is similar to a case statement in other languages. It takes a two parameter
predicate (this is mostly = or instance?) and an expression to act as its second argument.
After those it takes any number of value/result expression pairs that are evaluated in order.
If the predicate evaluates to true when one of the values is used as its first argument then
the corresponding result is returned. An optional final argument is the result to be returned if
no given value causes the predicate to evaluate to true. If this is omitted and no given value
causes the predicate to evaluate to true then an IllegalArgumentException is thrown:

(condp = 1
    1 "Clojure"
    2 "Ruby"
    3 "Java"
    "Sorry, no match")
; => "Clojure"
(condp = 5
    1 "Clojure"
    2 "Ruby"
    3 "Java"
    "Sorry, no match")
; => "Sorry, no match"



when, when-not

@ 2010 by Satish Talim                                                                  Page 37
Prepared exclusively for Clojure 101 Course participants



The when form is similar to the if form. The differences are that there is no "else" condition,
and more than one expression can be added to the when form for evaluation when the
condition is true.

(when true "do-this-first" "then-that" "finally this") ; => "finally this"



when-not is the opposite of when, in that it evaluates its body if the test returns false.

(when-not true "do-this-first" "then-that" "finally this") ; => nil
(when-not false "do-this-first" "then-that" "finally this") ; => "finally this"



do

The do form is used to execute a number of operations in sequence. Clojure provides the
println form for writing to standard output. In order to use println within an expression
whose return value we care about, we need to put it in a do expression:

(do (println "Hello.") (+ 2 2))
Hello.
4
(do (println "Hello.") (println "Hello again.") (+ 2 2))
Hello.
Hello again.
4



The do operation executes each expression in sequence and returns the result of the last
expression.

do is useful when you want to include a sequence of actions in a position where only a single
form is expected, e.g. for having various statements in a branch of an if.

Here's a contrived example:

(if (odd? 3) (println "First true form") (println "Second true form (will not
print)")) ; => First true form
(if (odd? 3) (do (println "First true form") (println "Second true form (will
print)")))
; => First true form
; => Second true form (will print)




@ 2010 by Satish Talim                                                                   Page 38
Prepared exclusively for Clojure 101 Course participants


if only accepts one form as if and else branch, so if you want to have several statements in
either, you'll have to wrap them in a do. In the first statement above, the second true from
will not print, since Clojure sees it as the else-branch. In the second it prints, because do is
considered one form.


Defining Functions

The defn macro defines a function. Its arguments are the function name, an optional
documentation string, the parameter list (specified with a vector that can be empty) and the
function body. The result of the last expression in the body is returned. Every function
returns a value, but it may be nil.

(defn my-function
  "returns a String"
  [name]
  (str "Goodbye, " name)) ; concatenation
(println (my-function "Satish")) ; => Goodbye, Satish



Function definitions must appear before their first use. Sometimes this isn't possible due to a
set of functions that invoke each other. The declare special form takes any number of
function names and creates forward declarations that resolve these cases:

(declare function-names)



defn- works just like defn but functions defined with the defn- macro are private and are
hardly secure. This means they are only visible in the namespace in which they are defined. It
is trivial to access a private var and as such, defn- should not be used as a security measure.
You could use defn- to create some helper functions that shouldn't be exposed outside the
namespace.

user> (ns sqr)
(defn- sq [x] (* x x))
(defn sum-of-squares [p q] (+ (sq p) (sq q)))
#'sqr/sum-of-squares
sqr> (sum-of-squares 4 5) ; => 41
sqr> (sq 5)
java.lang.Exception: Unable to resolve symbol: sq in this context



If you call a function with an incorrect number of arguments, Clojure will throw an
IllegalArgumentException.



@ 2010 by Satish Talim                                                                  Page 39
Prepared exclusively for Clojure 101 Course participants


Functions can take a variable number of parameters (note that there are no commas
delimiting the function parameters). Optional parameters must appear at the end. They are
gathered into a list by adding an ampersand and a name for the list at the end of the
parameter list:

(defn   dating    [person & who-all]
(println    person "are dating" (count who-all)            "people." ))
(dating "You" "1" "2" "3") ; => You are dating 3 people.
; dating function called with only the mandatory parameter
(dating "You") ; => You are dating 0 people.



Clojure functions are "first-class" functions i.e. Clojure functions can be stored, passed and
returned just as any other piece of data within that language. Thus, Clojure functions can be
stored in vars, held in lists and other collection types, be passed as arguments to and even
returned as the result of other functions.

Function definitions can contain more than one parameter list and corresponding body. Each
parameter list must contain a different number of parameters. This supports overloading
functions. Note that overloading of Clojure functions are based on arity (arity refers to the
differences in the argument count that a function will accept) and not on type:

(defn greet
    ([] (greet " world"))
    ([name] (str "Hello " name)))



Anonymous functions have no name. These are often passed as arguments to a named
function. When an anonymous function is defined using the fn special form, the body can
contain any number of expressions.

((fn [x] (+ x 1)) 9) ; => 10



Functions can be bound to a symbol:

(def plus-one
  (fn [x] (+ x 1)))
(plus-one 9) ; => 10



An anonymous function can also be defined in the short way using #(...). The parameters are
named %1, %2, and so on. You can also use % for the first parameter.

(#(apply str %1 %2) "Hello" " World") ; => Hello World



@ 2010 by Satish Talim                                                                Page 40
Prepared exclusively for Clojure 101 Course participants


Finally remember that, Clojure function calls are Java method calls.


Exercise 1

Write a method called convert that takes one argument which is a temperature in degrees
Fahrenheit. This method should return the temperature in degrees Celsius.

Sample Solution:

(defn convert
  [fahr]
  (float (* (- fahr 32) 5/9))) ; Note the use of Clojure Ratio
(println ( str "The temperature in Celcius = " (convert 75)))
; => The temperature in Celcius = 23.88889



Exercise 2

Write a method leap-year? It should have as an argument a year value, check whether it's a
leap year and then return true or false. A leap year is every 4 years, but not every 100 years,
then again every 400 years.

Sample Solution:

(defn leap-year?
  [input-year]
  (or (and (= (rem input-year 4) 0) (> (rem input-year 100) 0)) (= (rem input-year
400) 0)))
(leap-year? 2100) ; => false



Note:
        (= x y) - Here = is the equality function and returns true if x equals y, false if not.

        (rem num div) - Here rem gives us the remainder of dividing numerator by
        denominator.

        and macro evaluates exprs one at a time, from left to right. If a form returns logical
        false (nil or false), "and" returns that value and doesn't evaluate any of the other
        expressions, otherwise it returns the value of the last expr. (and) returns true.

        or macro evaluates exprs one at a time, from left to right. If a form returns a logical
        true value, "or" returns that value and doesn't evaluate any of the other expressions,
        otherwise it returns the value of the last expression. (or) returns nil.



@ 2010 by Satish Talim                                                                     Page 41
Prepared exclusively for Clojure 101 Course participants


Exercise 3

Create a divides? predicate that takes a dividend and a divisor, and returns true if divisor
evenly divides the dividend:

Sample Solution:

(defn divides?
  "Does divisor divide dividend evenly?"
  [dividend divisor]
  (zero? (rem dividend divisor)))



Note:
        zero? returns true if the argument to zero? is zero, else false.




@ 2010 by Satish Talim                                                              Page 42
Prepared exclusively for Clojure 101 Course participants


Documentation


Using doc

Nearly all the forms in Clojure have built-in documentation. If you want to read the doc at
the REPL, you can just ask for the function’s doc string:

user > (doc first)
-------------------------
clojure/first
([coll])
  Returns the first item in the collection. Calls seq on its
      argument. If coll is nil, returns nil.
nil
user >



doc will also tell you if a form is implemented as a macro:

user > (doc and)
-------------------------
clojure.core/and
([] [x] [x & next])
Macro
  Evaluates exprs one at a time, from left to right. If a form
  returns logical false (nil or false), and returns that value and
  doesn't evaluate any of the other expressions, otherwise it returns
  the value of the last expr. (and) returns true.
nil
user >



find-doc

The find-doc function will search for anything whose doc output matches a regular expression
or string you pass in. Example:

(find-doc "list")



Regular expressions in Clojure look like strings prepended by an #. Use a regular expression to
find all the find- functions:

(find-doc #"find-w+")


@ 2010 by Satish Talim                                                                 Page 43
Prepared exclusively for Clojure 101 Course participants


Documenting a function

Every function can have a doc description (similar to Javadoc) attached to it, like:

user > (defn plus-one
  "Returns a number one greater than x"
  [x]
  (+ x 1))
#'user/plus-one
user > (doc plus-one)
-------------------------
user/plus-one
([x])
  Returns a number one greater than x
nil
user >



Clojure API

Clojure’s complete API is documented online at http://clojure.org/api. The right sidebar links
to all functions and macros by name, and the left sidebar links to a set of overview articles on
various Clojure features.




@ 2010 by Satish Talim                                                                  Page 44
Prepared exclusively for Clojure 101 Course participants




CLOJURE AND JAVA


Working with Java

Note: This section requires you to have knowledge of the Java programming language.


Importing multiple classes

Note: Clojure programs can use all Java classes and interfaces. As in Java, classes in the
java.lang package can be used without importing them. Java classes in other packages can be
used by either specifying their package when referencing them or using the import function
(use import to refer to Java classes in the current namespace).

(import   'java.util.Random)



import also takes a variable number of lists, with the first part of each list being a package
name and the rest being names to import from that package:

(import   '(java.util     Random    Locale)
          '(java.text     MessageFormat))



Create a Java object

Assuming that you have used the import form as shown above, we can create a Java object of
Random as follows:

(Random.) ; note the .



Note the existence of the (new) special form. The (ClassName.) form is simply a macro for
(new ClassName):

(macroexpand '(Date.)) ; => (new Date)



Note: The macroexpand function returns a macro form's expansion.
http://richhickey.github.com/clojure/clojure.core-api.html#clojure.core/macroexpand




@ 2010 by Satish Talim                                                                Page 45
Prepared exclusively for Clojure 101 Course participants


To use a Random, you will need to save it away somewhere. For now, simply use def to save
the Random into a Clojure var:

(import     '(java.util      Random))
(def rnd (Random.))



Accessing methods

Random also has a nextInt( ) method that takes an argument. You can call it by:

(import     '(java.util   Random))
(def rnd (Random.))
(.nextInt rnd 10)



Also, note that (.methodName obj) is a macro for (. obj methodName):

(macroexpand '(.toString (Date.))) ; => (. (Date.) toString)



If you can't remember all the methods in the Random class, you can pass either a class or an
instance to javadoc:

(javadoc java.util.Random)



..chains

The (..) macro chains together multiple member accesses by making each result the this
object for the next member access in the chain. Thus looking up an object’s code URL
becomes the following:

(..   '(1    2)   getClass    getProtectionDomain     getCodeSource   getLocation)



Note:
        The .. reads left to right, like Java. The .. macro is great if the result of each
        operation is an input to the next.

        It is possible to pass arguments in the intermediate function calls.




@ 2010 by Satish Talim                                                               Page 46
Prepared exclusively for Clojure 101 Course participants


doto

Sometimes you don’t care about the results of method calls and simply want to make several
calls on the same object. The doto macro makes it easy to make several calls on the same
object. For example, use doto to set multiple system properties:

(doto    (System/getProperties)
  (.setProperty     "name"    "Stuart")
  (.setProperty     "favoriteColor"      "blue"))



doto returns the object at the end. This is very useful for Java Swing classes:

(doto (javax.swing.JPanel.) (.setEnabled false) (.setToolTipText "Not available"))
; => #<JPanel
javax.swing.JPanel[,0,0,0x0,invalid,disabled,layout=java.awt.FlowLayout,alignmentX=0.0
,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=]>



Accessing static fields

(Math/PI) ; => 3.141592653589793
(System/getProperty "java.home") ; => "C:Program FilesJavajdk1.6.0_20jre"



Accessing static methods

For static methods, you can use (Classname/membername):

(System/currentTimeMillis) ; => 1272362112453



-> macro

(import [java.util Date Random])
(Date. (long (.nextInt (Random.)))) ; => #<Date Sat Jan 10 06:37:47 IST 1970>



In the above code, starting from the inside, you:

    1.   get a new Random
    2.   get the next random integer
    3.   cast it to a long
    4.   pass the long to the Date constructor




@ 2010 by Satish Talim                                                            Page 47
Prepared exclusively for Clojure 101 Course participants


The above is a bit confusing for beginners new to Clojure. You don't have to write inside-out
code in Clojure. The -> macro takes its first form, and passes it as the first argument to its
next form. The result then becomes the first argument of the next form, and so on. It is
easier to read than to describe:


(import [java.util Date Random])
(-> (Random.) (.nextInt) (long) (Date.)) ; => #<Date Sat Jan 10 06:37:47 IST 1970>



Exception handling

All exceptions thrown by Clojure code are runtime exceptions. Java methods invoked from
Clojure code can still throw checked exceptions. In Clojure, you are not forced to deal with
checked exceptions. You do not have to catch them or declare that you throw them. The try,
catch, finally and throw special forms provide functionality similar to their Java
counterparts.

Let's look at an example:

(/ 1 0) ; => java.lang.ArithmeticException: Divide by zero



In the above case we see an java.lang.ArithmeticException being thrown. This is a runtime
exception which is thrown by the underlying JVM.

The following shows how runtime exceptions like java.lang.ArithmeticException can be
handled:

(try (/ 1 0)
       (catch Exception e (prn "in catch"))
       (finally (prn "in finally")))
"in catch"
"in finally"
nil



Note: The pr and prn functions prints the object(s) to the output stream that is the current
value of *out*. pr prints the object(s), separated by spaces if there is more than one. By
default, pr and prn print in a way that objects can be read by the reader. prn is the same as
pr followed by (newline).




@ 2010 by Satish Talim                                                                Page 48
Prepared exclusively for Clojure 101 Course participants


Some More Examples

(.toUpperCase "hello") ; => HELLO
(.length "hello") ; => 5



In the next example, let's write a parse helper function:

(defn parse [s]
  (try (Double/parseDouble (.trim s))
        (catch NumberFormatException e nil)))
(parse "22") ; => 22.0
(parse "       23.45     ") ; => 23.45
(parse "asas") ; => nil



In the following example, the display helper function takes a number, rounds it to the
nearest Integer (because Integers are prettier), and returns a String:

(defn display [n]
  (str (Math/round (float n))))
(display 22.5) ; => "23"
(display 22/7) ; => "3"



Source for a function

You can use Clojure to tell you the source for a function. To use this functionality, you’ll need
to import the repl-utils library:

user> (use 'clojure.contrib.repl-utils)
nil
user> (source println)
(defn println
  "Same as print followed by (newline)"
  [& more]
      (binding [*print-readably* nil]
        (apply prn more)))
nil
user>



Inspector

One useful utility built into Clojure is the ability to pop up a Swing app that can inspect a
data structure.

@ 2010 by Satish Talim                                                                   Page 49
Prepared exclusively for Clojure 101 Course participants


http://richhickey.github.com/clojure/clojure.inspector-api.html


To start using it, type:

(use 'clojure.inspector) ; => nil



You can use the generic inspect function to look at arbitrary objects:

(inspect (System/getProperties))




@ 2010 by Satish Talim                                                   Page 50
Prepared exclusively for Clojure 101 Course participants



DIVING INTO CLOJURE

Namespaces

Clojure partitions things that are named by symbols into namespaces. There is always a
current default namespace, initially set to "user", and it is stored in the special symbol *ns*.
The "user" namespace provides access to all the symbols in the clojure.core namespace.

Clojure respects Java naming conventions for directories and files, but Lisp naming
conventions for namespace names. So a Clojure namespace com.my-app.utils would live in a
path named com/my_app/utils.clj. Note especially the underscore/hyphen distinction.


in-ns function

The default namespace can be changed by the in-ns function. Let's create a "notes"
namespace:

(in-ns 'notes) ; => #<Namespace notes>



Now you are in the "notes" namespace, and anything you def or defn will belong to "notes".
When you create a new namespace with in-ns, the java.lang package is automatically
available to you.


ns

The general form of the ns macro is:

(ns name & references)



The default namespace can be changed by the ns macro. The name, as mentioned above, is
the name of the namespace being made current. If it doesn't already exist, it gets created.
The references that follows the name are optional, and can be one or more of the following –
use, require, import, load, gen-class, or load.

The ns macro will create a new namespace that contains mappings for the classnames in
java.lang and for the functions in clojure.core.

Note: In order to access items that are not in the default namespace they must be
namespace-qualified. This is done by preceding a name with a namespace name and a slash
(whereas Java package names are separated from a class name with a period). Use “use” to
@ 2010 by Satish Talim                                                                  Page 51
Prepared exclusively for Clojure 101 Course participants


load and refer Clojure libraries. For example, the round function lives in
clojure.contrib.math. In order to make round available in the current namespace, call use
on round's namespace:

(use   'clojure.contrib.math) ; => nil



The simple form of use shown above causes the current namespace to refer to all public vars
in clojure.contrib.math. This can be confusing, because it does not make explicit which
names are being referred to. Remember to pass the :only option to use, listing only the vars
you need:

(use   '[clojure.contrib.math       :only   (round)]) ; => nil



Now you can call round without having to qualify its name:

(round   1.6) ; => 2



The ns macro, mentioned earlier, changes the default namespace. It is typically used at the
top of a source file. It supports the directives :require, :use and :import (for importing Java
classes) that are alternatives to using their function forms. Using these is preferred over using
their function forms. Here, symbols become keywords, and quoting is no longer required.

(ns notes
  (:use [clojure.contrib.math :only (gcd, sqrt)])
  (:import (java.text NumberFormat) (javax.swing JFrame JLabel)))
(println (gcd 27 81)) ; => 27
(println (sqrt 7)) ; => 2.6457513110645907
(println (.format (NumberFormat/getInstance) Math/PI)) ; => 3.142
; the code below requires you to have knowledge of the Java programming language
; also see the generated image below
(doto (JFrame. "Hello")
  (.add (JLabel. "Hello, World!"))
  (.pack)
  (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
  (.setVisible true))




@ 2010 by Satish Talim                                                                   Page 52
Prepared exclusively for Clojure 101 Course participants




More on Bindings

An example:

(def cnt 1) ; cnt is a global binding
(defn fn1
  []
  (println "Global binding value of fn1 = " cnt))
(fn1) ; Global binding value of fn1 =          1



let

The let special form creates bindings that are local to that form. Its first argument is a vector
containing name/expression pairs. The expressions are evaluated in order (i.e. let does its
bindings sequentially) and their results are assigned to the names on their left. These
bindings can be used in the expressions that follow them in the vector. They can also be
assigned to more than once to change their value. The remaining arguments to let comprise
the body which is a set of expressions to be evaluated with the new bindings in scope.
Functions that are called in the body cannot see the local bindings created by let. Do check-
out the let documentation.
http://clojure.org/special_forms#let




@ 2010 by Satish Talim                                                                   Page 53
Prepared exclusively for Clojure 101 Course participants


An example:

(def x 1)
(def y 1)
(let [x 2 y x]
  (+ x y)) ; => 4
x ; => 1
y ; => 1



Another example:

(def cnt 1) ; cnt is a global binding
(defn fn1
  []
  (println "Global binding value in fn1 = " cnt))
(defn fn2
  []
  (println "fn2: before let cnt (still global binding) =" cnt)          ; fn2: before let cnt
(still global binding) = 1
  (let [cnt 2]                        ; creates local binding cnt that shadows global one
    (println "fn2: in let, cnt (now local binding) =" cnt)              ; fn2: in let, cnt
(now local binding) = 2
    (fn1))                                                 ; Global binding value in fn1 =   1
  (println "fn2: after let cnt (back to global binding) =" cnt)) ; fn2: after let cnt
(back to global binding) = 1
(fn2)



binding

The binding special form is similar to let, but it temporarily gives new, thread-local values to
existing global bindings. The new values are seen inside that form and also in functions called
from inside it. When the binding form exits, the bindings revert to their previous values.

An example:

Observe below that binding does its bindings in parallel.

(def x 1)
(def y 1)
(binding [x 2 y x]
  (+ x y)) ; => 3
x ; => 1
y ; => 1


@ 2010 by Satish Talim                                                                  Page 54
Prepared exclusively for Clojure 101 Course participants


Another example:

(def cnt 1) ; cnt is a global binding
(defn fn1
  []
  (println "Global binding value in fn1 = " cnt))
(defn fn3
  []
  (println "fn3: before binding cnt (still global binding) =" cnt)
; fn3: before binding cnt (still global binding) = 1
  (binding [cnt 3]
; same global binding with new, temporary value
    (println "fn3: in binding, cnt (global binding value temporarily changed) =" cnt)
; fn3: in binding, cnt (global binding value temporarily changed) = 3
    (fn1))
; Global binding value in fn1 =         3
  (println "fn3: after binding cnt (value of global binding reverted back) =" cnt))
; fn3: after binding cnt (value of global binding reverted back) = 1
(fn3)



Symbols that are intended to be bound to new, thread-local values using binding have their
own naming convention. These special symbols have names that begin and end with an
asterisk. People sometimes refer to the asterisks as "earmuffs".

For example, Clojure uses dynamic binding for thread-wide options such as the standard I/O
streams *in*, *out* and *err*. The predefined, special symbols *in*, *out* and *err* are set
to stdin, stdout and stderr by default. Functions that use these bindings are affected by their
values. For example, binding a new value to *out* changes the output destination of the
println function.

Guideline: As far as possible use let. Use binding when you need a thread-local version of a
var.


Echo Server

We shall build a simple server that accepts network connections and simply echoes back
whatever was sent.


Port

A port is not a physical device, but an abstraction to facilitate communication between a
server and a client.

@ 2010 by Satish Talim                                                                 Page 55
Prepared exclusively for Clojure 101 Course participants


Ports are described by a 16-bit integer value. Hence, a machine can have a maximum of
65536 port numbers (ranging from 0 to 65535). The port numbers are divided into three
ranges: the Well Known Ports, the Registered Ports, and the Dynamic and/or Private Ports.
The Well Known Ports are those from 0 through 1023 (for example, port no. 80 is for http,
port no. 25 is for smtp and so on). The Registered Ports are those from 1024 through 49151.
The Dynamic and/or Private Ports are those from 49152 through 65535.


Socket

A socket is not a physical device but an abstraction. It represents a single connection between
two network applications. These two applications normally run on different computers, but
sockets can also be used for inter-process communication on a single computer. Applications
can create multiple sockets for communicating with each other. Sockets are bidirectional,
meaning that either side of the connection is capable of both sending and receiving data.


clojure-contrib library

The user contributions library, clojure.contrib, is a collection of namespaces each of which
implements features that may be useful to a large part of the Clojure community. Some parts
of clojure.contrib may migrate into clojure.core if they prove to be so generally useful.

See the clojure.contrib API here - http://richhickey.github.com/clojure-contrib/index.html.


server-socket API

To build this simple server, we shall make use of the server-socket API from the
clojure.contrib library. We shall use the following from this API:
http://richhickey.github.com/clojure-contrib/server-socket-api.html



(ns your-namespace
  (:require clojure.contrib.server-socket))
(create-server port fun)



The above code creates a server socket on port. When accepting a connection, a new thread
is created which calls:

(fun input-stream output-stream)




@ 2010 by Satish Talim                                                                 Page 56
Prepared exclusively for Clojure 101 Course participants


duck-streams API

We shall also make use of the duck-streams API from the clojure.contrib library. We shall
use the following from this API:
http://richhickey.github.com/clojure-contrib/duck-streams-api.html



(ns your-namespace
  (:require clojure.contrib.duck-streams))



This library defines "duck-typed" I/O utility functions for Clojure. The 'reader' and 'writer'
functions will open and return an instance of java.io.BufferedReader and
java.io.PrintWriter, respectively, for a variety of argument types - filenames as strings,
URLs, java.io.File's, etc. 'reader' even works on HTTP URLs.


spit function

Let’s make a little diversion. We shall have a look at the spit function from the
clojure.contrib library. This function is not used in the Echo Server.

Usage:

(spit f content)



Opens f with writer, writes content, then closes f.

Here's an example:

(use    '[clojure.contrib.duck-streams        :only   (spit)])
(spit    "rubylearning.out"     "Hello    RubyLearning participants.")



You should now find a file at rubylearning.out with contents Hello RubyLearning
participants.


Step 1: Define a namespace

(ns echo
  (:use [clojure.contrib server-socket duck-streams]))




@ 2010 by Satish Talim                                                                Page 57
Prepared exclusively for Clojure 101 Course participants


Step 2: Define a port

(def port 2222)



Our server socket would be listening on this port defined by the port variable.


Step 3: Define a function

Our function handle-client takes two arguments named in and out. In this case it will be
streams attached to the client's socket.

binding binds names to new values temporarily. in and out are the default streams that the
standard IO functions read from (stdin) and write to (stdout). But within the body of this
binding block, they will now refer to readers and writers for the client socket. This way we
can use functions like read-line and println to communicate with the client. In fact, in our
block we read a line and print it out. loop begins the loop and recur returns to the start of
the loop.

(defn handle-client [in out]
  (binding [*in* (reader in)
               *out* (writer out)]
    (loop []
       (println (read-line))
       (recur))))



Step 4: Start the server

To start the server, type the following in your REPL:

(def server (create-server port handle-client))



Finally we call create-server with two arguments - the port number and the function we
want to handle the client connections. We keep this in the server var. A lot of the
concurrency issues are handled by Clojure inside the create-server function. We don't have to
worry about firing-up threads or doing other kinds of listeners. It will handle that under the
covers. So that's it for a simple echo server. Our echo server is running at port 2222 on
localhost.




@ 2010 by Satish Talim                                                                Page 58
Prepared exclusively for Clojure 101 Course participants


Here's the complete code of our Echo Server:

(ns echo
  (:use [clojure.contrib server-socket duck-streams]))
(def port 2222)
(defn handle-client [in out]
  (binding [*in* (reader in)
                     *out* (writer out)]
    (loop []
        (println (read-line))
        (recur))))
(def server (create-server port handle-client))



Step 5: Test the Echo Server

Open a command window and use Telnet to connect to our Echo Server:

telnet localhost 2222



Now anything I type in will be echoed back.


StructMaps

The defstruct macro is used to define a StructMap:

(defstruct account-struct       :name :balance)



The structure field names of type keyword or symbols are automatically usable as functions to
access fields of the structure. This is possible as structures are maps and this feature is
supported by maps. This is not possible for other types of field names such as strings or
numbers. It is quite common to use keywords for field names for structures due to the above
reason.

The object returned by defstruct is what is called the structure basis. This is not a structure
instance but contains information of what the structure instances should look like.




@ 2010 by Satish Talim                                                                 Page 59
Clojure forbeginners
Clojure forbeginners
Clojure forbeginners
Clojure forbeginners
Clojure forbeginners
Clojure forbeginners
Clojure forbeginners
Clojure forbeginners

Weitere ähnliche Inhalte

Was ist angesagt?

Link SDVOSB Past Performance Summaries
Link SDVOSB Past Performance SummariesLink SDVOSB Past Performance Summaries
Link SDVOSB Past Performance Summariesgasanden
 
App designprocess(yukijiang)
App designprocess(yukijiang)App designprocess(yukijiang)
App designprocess(yukijiang)Xue Jiang
 
Tellurium 0.6.0 User Guide
Tellurium 0.6.0 User GuideTellurium 0.6.0 User Guide
Tellurium 0.6.0 User GuideJohn.Jian.Fang
 
Tarion Construction Performance Guidelines 3rd edition 2012 final
Tarion Construction Performance Guidelines 3rd edition 2012 finalTarion Construction Performance Guidelines 3rd edition 2012 final
Tarion Construction Performance Guidelines 3rd edition 2012 finalSteven Silva
 

Was ist angesagt? (6)

Link SDVOSB Past Performance Summaries
Link SDVOSB Past Performance SummariesLink SDVOSB Past Performance Summaries
Link SDVOSB Past Performance Summaries
 
developersguide.pdf
developersguide.pdfdevelopersguide.pdf
developersguide.pdf
 
App designprocess(yukijiang)
App designprocess(yukijiang)App designprocess(yukijiang)
App designprocess(yukijiang)
 
Tellurium 0.6.0 User Guide
Tellurium 0.6.0 User GuideTellurium 0.6.0 User Guide
Tellurium 0.6.0 User Guide
 
Tarion Construction Performance Guidelines 3rd edition 2012 final
Tarion Construction Performance Guidelines 3rd edition 2012 finalTarion Construction Performance Guidelines 3rd edition 2012 final
Tarion Construction Performance Guidelines 3rd edition 2012 final
 
Icp
IcpIcp
Icp
 

Andere mochten auch

2010 05-20-clojure concurrency--jugd
2010 05-20-clojure concurrency--jugd2010 05-20-clojure concurrency--jugd
2010 05-20-clojure concurrency--jugdKwanzoo Dev
 
Programming.clojure
Programming.clojureProgramming.clojure
Programming.clojureKwanzoo Dev
 
Hickey jvm summit2009
Hickey jvm summit2009Hickey jvm summit2009
Hickey jvm summit2009Kwanzoo Dev
 
Getting started erlang
Getting started erlangGetting started erlang
Getting started erlangKwanzoo Dev
 
Hello, android introducing google’s mobile development platform, 2nd editio...
Hello, android   introducing google’s mobile development platform, 2nd editio...Hello, android   introducing google’s mobile development platform, 2nd editio...
Hello, android introducing google’s mobile development platform, 2nd editio...Kwanzoo Dev
 
Profession android application development
Profession android application developmentProfession android application development
Profession android application developmentKwanzoo Dev
 
Study: The Future of VR, AR and Self-Driving Cars
Study: The Future of VR, AR and Self-Driving CarsStudy: The Future of VR, AR and Self-Driving Cars
Study: The Future of VR, AR and Self-Driving CarsLinkedIn
 

Andere mochten auch (7)

2010 05-20-clojure concurrency--jugd
2010 05-20-clojure concurrency--jugd2010 05-20-clojure concurrency--jugd
2010 05-20-clojure concurrency--jugd
 
Programming.clojure
Programming.clojureProgramming.clojure
Programming.clojure
 
Hickey jvm summit2009
Hickey jvm summit2009Hickey jvm summit2009
Hickey jvm summit2009
 
Getting started erlang
Getting started erlangGetting started erlang
Getting started erlang
 
Hello, android introducing google’s mobile development platform, 2nd editio...
Hello, android   introducing google’s mobile development platform, 2nd editio...Hello, android   introducing google’s mobile development platform, 2nd editio...
Hello, android introducing google’s mobile development platform, 2nd editio...
 
Profession android application development
Profession android application developmentProfession android application development
Profession android application development
 
Study: The Future of VR, AR and Self-Driving Cars
Study: The Future of VR, AR and Self-Driving CarsStudy: The Future of VR, AR and Self-Driving Cars
Study: The Future of VR, AR and Self-Driving Cars
 

Ähnlich wie Clojure forbeginners

User-guide Tool Book 11
User-guide Tool Book 11User-guide Tool Book 11
User-guide Tool Book 11William Finol
 
Kotlin notes for professionals
Kotlin notes for professionalsKotlin notes for professionals
Kotlin notes for professionalsZafer Galip Ozberk
 
ARQUIVO ROUBADO
ARQUIVO ROUBADOARQUIVO ROUBADO
ARQUIVO ROUBADOD813061988
 
The Japanese Knotweed Bible - TP Knotweed Solutions
The Japanese Knotweed Bible - TP Knotweed SolutionsThe Japanese Knotweed Bible - TP Knotweed Solutions
The Japanese Knotweed Bible - TP Knotweed SolutionsTP Knotweed Solutions
 
pdfcoffee.com_livecode-userguide-pdf-free.pdf
pdfcoffee.com_livecode-userguide-pdf-free.pdfpdfcoffee.com_livecode-userguide-pdf-free.pdf
pdfcoffee.com_livecode-userguide-pdf-free.pdftrasserra1
 
developersguide.pdf
developersguide.pdfdevelopersguide.pdf
developersguide.pdfjcarrey
 
developersguide.pdf
developersguide.pdfdevelopersguide.pdf
developersguide.pdfjcarrey
 
developersguide.pdf
developersguide.pdfdevelopersguide.pdf
developersguide.pdfjcarrey
 

Ähnlich wie Clojure forbeginners (20)

E100 manual
E100 manualE100 manual
E100 manual
 
User-guide Tool Book 11
User-guide Tool Book 11User-guide Tool Book 11
User-guide Tool Book 11
 
Ozp user guide
Ozp user guideOzp user guide
Ozp user guide
 
Kotlin notes for professionals
Kotlin notes for professionalsKotlin notes for professionals
Kotlin notes for professionals
 
perl_tk_tutorial
perl_tk_tutorialperl_tk_tutorial
perl_tk_tutorial
 
perl_tk_tutorial
perl_tk_tutorialperl_tk_tutorial
perl_tk_tutorial
 
ARQUIVO ROUBADO
ARQUIVO ROUBADOARQUIVO ROUBADO
ARQUIVO ROUBADO
 
The Japanese Knotweed Bible - TP Knotweed Solutions
The Japanese Knotweed Bible - TP Knotweed SolutionsThe Japanese Knotweed Bible - TP Knotweed Solutions
The Japanese Knotweed Bible - TP Knotweed Solutions
 
Ise syllabus 2010 2013
Ise syllabus 2010 2013Ise syllabus 2010 2013
Ise syllabus 2010 2013
 
pdfcoffee.com_livecode-userguide-pdf-free.pdf
pdfcoffee.com_livecode-userguide-pdf-free.pdfpdfcoffee.com_livecode-userguide-pdf-free.pdf
pdfcoffee.com_livecode-userguide-pdf-free.pdf
 
developersguide.pdf
developersguide.pdfdevelopersguide.pdf
developersguide.pdf
 
developersguide.pdf
developersguide.pdfdevelopersguide.pdf
developersguide.pdf
 
developersguide.pdf
developersguide.pdfdevelopersguide.pdf
developersguide.pdf
 
developersguide.pdf
developersguide.pdfdevelopersguide.pdf
developersguide.pdf
 
developersguide.pdf
developersguide.pdfdevelopersguide.pdf
developersguide.pdf
 
developersguide.pdf
developersguide.pdfdevelopersguide.pdf
developersguide.pdf
 
developersguide.pdf
developersguide.pdfdevelopersguide.pdf
developersguide.pdf
 
developersguide.pdf
developersguide.pdfdevelopersguide.pdf
developersguide.pdf
 
developersguide.pdf
developersguide.pdfdevelopersguide.pdf
developersguide.pdf
 
developersguide.pdf
developersguide.pdfdevelopersguide.pdf
developersguide.pdf
 

Kürzlich hochgeladen

Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024TopCSSGallery
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesMuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesManik S Magar
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfNeo4j
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfpanagenda
 
React Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkReact Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkPixlogix Infotech
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityIES VE
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentPim van der Noll
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Nikki Chapple
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsRavi Sanghani
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationKnoldus Inc.
 

Kürzlich hochgeladen (20)

Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesMuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdf
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
 
React Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkReact Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App Framework
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a reality
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and Insights
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog Presentation
 

Clojure forbeginners

  • 1. @ 2010 by Satish Talim
  • 2. Prepared exclusively for Clojure 101 Course participants Clojure for Beginners Copyright (c) 2010 Satish Talim http://satishtalim.com/ Warning and Disclaimer Every effort has been made to make this book as complete and as accurate as possible, but no warranty of fitness is implied. The information provided is on an "as is" basis. The author shall have neither liability nor responsibility to any person or entity with respect to any loss or damages arising from the information contained in this book. Revised Edition – 27th May 2010 First Edition – May 2010 PLEASE SUPPORT RUBYLEARNING.COM @ 2010 by Satish Talim Page 2
  • 3. Prepared exclusively for Clojure 101 Course participants Clojure Notes Contents Acknowledgements .................................................................................................................................... 8 ABOUT THE EBOOK ................................................................................................................................... 10 Assumptions ............................................................................................................................................................................. 10 Concept and Approach ........................................................................................................................................................ 10 How to Use This Clojure eBook ....................................................................................................................................... 10 About the Conventions Used in This Clojure eBook .............................................................................................. 11 Learn Clojure Online and for Free.................................................................................................................................. 11 INTRODUCTION TO CLOJURE .................................................................................................................... 12 What is Clojure? ...................................................................................................................................................................... 12 GETTING STARTED .................................................................................................................................... 14 Labrepl Download and Installation (for MS Windows)....................................................................................... 14 What's Labrepl? ................................................................................................................................ 14 Downloading and Installing Labrepl (for MS Windows) .................................................................... 14 Starting the REPL ............................................................................................................................... 15 Loading a file in the REPL .................................................................................................................. 16 Clojure Box Download and Installation (for MS Windows) .............................................................................. 16 Test if Clojure Box works ................................................................................................................... 17 Loading a file in Clojure Box .............................................................................................................. 17 NetBeans/Enclojure Download and Installation (for MS Windows) ............................................................ 18 To create a Clojure Project in NetBeans............................................................................................ 19 @ 2010 by Satish Talim Page 3
  • 4. Prepared exclusively for Clojure 101 Course participants To start the REPL in NetBeans ........................................................................................................... 19 Anatomy of the Enclojure REPL Panel ............................................................................................... 19 Syntax .......................................................................................................................................................................................... 19 Comments .................................................................................................................................................................................. 19 Clojure Coding Guidelines & Naming Convention ............................................................................................. 20 Forms ........................................................................................................................................................................................... 21 Symbols ....................................................................................................................................................................................... 21 Vars and Bindings.................................................................................................................................................................. 22 Literals......................................................................................................................................................................................... 23 Booleans and nil ................................................................................................................................ 23 Numbers ........................................................................................................................................... 23 Characters and Strings ...................................................................................................................... 25 Keywords .......................................................................................................................................... 26 Exercises ..................................................................................................................................................................................... 26 Exercise 1 .......................................................................................................................................... 26 Exercise 2 .......................................................................................................................................... 27 CHARGING AHEAD .................................................................................................................................... 28 A Quick look at Collections ................................................................................................................................................ 28 Lists ................................................................................................................................................... 28 Vectors .............................................................................................................................................. 29 Sets ................................................................................................................................................... 29 Maps ................................................................................................................................................. 30 Some functions on collections .......................................................................................................... 31 Sequences .................................................................................................................................................................................. 32 seq .................................................................................................................................................... 32 @ 2010 by Satish Talim Page 4
  • 5. Prepared exclusively for Clojure 101 Course participants first.................................................................................................................................................... 32 rest .................................................................................................................................................... 33 cons................................................................................................................................................... 33 next ................................................................................................................................................... 33 conj, into ........................................................................................................................................... 34 range ................................................................................................................................................. 34 repeat ............................................................................................................................................... 34 iterate, take ...................................................................................................................................... 34 concat ............................................................................................................................................... 35 Flow Control ............................................................................................................................................................................. 35 if, if-not ............................................................................................................................................. 36 cond, condp ...................................................................................................................................... 36 when, when-not ................................................................................................................................ 37 do ...................................................................................................................................................... 38 Defining Functions................................................................................................................................................................. 39 Exercise 1 .......................................................................................................................................... 41 Exercise 2 .......................................................................................................................................... 41 Exercise 3 .......................................................................................................................................... 42 Documentation ........................................................................................................................................................................ 43 Using doc .......................................................................................................................................... 43 find-doc ............................................................................................................................................. 43 Documenting a function ................................................................................................................... 44 Clojure API ........................................................................................................................................ 44 CLOJURE AND JAVA................................................................................................................................... 45 Working with Java ................................................................................................................................................................. 45 @ 2010 by Satish Talim Page 5
  • 6. Prepared exclusively for Clojure 101 Course participants Importing multiple classes ................................................................................................................ 45 Create a Java object .......................................................................................................................... 45 Accessing methods ........................................................................................................................... 46 ..chains .............................................................................................................................................. 46 doto .................................................................................................................................................. 47 Accessing static fields........................................................................................................................ 47 Accessing static methods .................................................................................................................. 47 -> macro ............................................................................................................................................ 47 Exception handling............................................................................................................................ 48 Some More Examples ....................................................................................................................... 49 Source for a function......................................................................................................................... 49 Inspector ........................................................................................................................................... 49 DIVING INTO CLOJURE .............................................................................................................................. 51 Namespaces .............................................................................................................................................................................. 51 in-ns function .................................................................................................................................... 51 ns ...................................................................................................................................................... 51 More on Bindings ................................................................................................................................................................... 53 let ...................................................................................................................................................... 53 binding .............................................................................................................................................. 54 Echo Server ............................................................................................................................................................................... 55 Port ................................................................................................................................................... 55 Socket ............................................................................................................................................... 56 clojure-contrib library ....................................................................................................................... 56 server-socket API .............................................................................................................................. 56 duck-streams API .............................................................................................................................. 57 @ 2010 by Satish Talim Page 6
  • 7. Prepared exclusively for Clojure 101 Course participants Step 1: Define a namespace .............................................................................................................. 57 Step 2: Define a port ......................................................................................................................... 58 Step 3: Define a function................................................................................................................... 58 Step 4: Start the server ..................................................................................................................... 58 Step 5: Test the Echo Server ............................................................................................................. 59 StructMaps ................................................................................................................................................................................ 59 Refs................................................................................................................................................................................................ 61 Transactions ............................................................................................................................................................................. 61 A Simple Accounts example .............................................................................................................. 63 Compiling using Clojure Box .......................................................................................................................................... 64 About the Author ...................................................................................................................................... 67 @ 2010 by Satish Talim Page 7
  • 8. Prepared exclusively for Clojure 101 Course participants Acknowledgements My interest in Clojure was aroused when Michael Kohl organized the first-ever, free, four- week, online Clojure course on RubyLearning.org – http://rubylearning.com/blog/2010/03/09/clojure-101-a-new-course/ (for people with some background in Lisp and / or Clojure.) Having had no previous exposure to Lisp and Clojure, I could not keep up with the others in the course after the first week. I decided to start making these study notes from the perspective of a beginner in Lisp and Clojure but with some experience in other programming languages. There are a good number of people who deserve thanks for their help and support they provided, either before or while this eBook is being written, and there are still others whose help will come after the eBook is released. I would specially like to thank Baishampayan Ghose, Daniel Solano Gomez and Michael Kohl for offering suggestions and proofreading these study notes. The material in these study notes is drawn primarily from the references mentioned below. My acknowledgment and thanks to all of them. Clojure Home http://clojure.org/ Clojure - Functional Programming for the JVM by R. Mark Volkmann – http://java.ociweb.com/mark/clojure/article.html Programming Clojure by Stuart Halloway – http://www.pragprog.com/titles/shcloj/programming-clojure The Joy of Clojure by Michael Fogus and Chris Houser – http://www.manning.com/fogus/ Clojure in Action by Amit Rathore – http://www.manning.com/rathore/ Practical Clojure by Luke Van der Hart – http://apress.com/book/view/1430272317 Clojure Programming/Concepts – http://en.wikibooks.org/wiki/Clojure_Programming/Concepts @ 2010 by Satish Talim Page 8
  • 9. Prepared exclusively for Clojure 101 Course participants Functional Programming with Clojure Screencast by PeepCode – http://peepcode.com/products/functional-programming-with-clojure @ 2010 by Satish Talim Page 9
  • 10. Prepared exclusively for Clojure 101 Course participants ABOUT THE EBOOK Assumptions These study notes are for absolute beginners in Clojure. Some previous programming background is essential. Some parts require knowledge of Java. The programs in these study notes have been tested using the Clojure 1.1 version. Since I have a Windows box, I have mentioned the installation of Clojure and other dependencies for MS Windows only. Concept and Approach I have tried to organize this eBook in which each chapter builds upon the skills acquired in the previous chapter, so that you will never be called upon to do something that you have not already learned. This eBook not only teaches you how to do something, but also provides you with the chance to put those morsels of knowledge into practice with exercises. I have therefore included several exercises, or assignments, in this eBook so that you will have opportunities to apply your knowledge. How to Use This Clojure eBook I recommend that you go through the entire Clojure eBook chapter by chapter, reading the text, running the sample programs and doing the assignments along the way. There are no large applications in this book – just small, self-contained sample programs. This will give you a much broader understanding of how things are done (and of how you can get things done), and it will reduce the chance of anxiety, confusion, and worse yet, mistakes. It is best to read this eBook and complete its assignments when you are relaxed and have time to spare. Nothing makes things go wrong more than working in a rush. And keep in mind that Clojure and the assignments in this eBook are fun, not just work exercises. So go ahead and enjoy it. @ 2010 by Satish Talim Page 10
  • 11. Prepared exclusively for Clojure 101 Course participants About the Conventions Used in This Clojure eBook Explanatory notes (generally provides some hints or gives a more in-depth explanation of some point mentioned in the text) are shown shaded like this: This is an explanatory note. You can skip it if you like - but if you do so, you may miss something of interest! Any source code in this Clojure eBook, is written like this: (defn greet ([] (greet " world")) ([name] (str "Hello " name))) When there is a sample program to accompany the code, the program name is shown like this: program.clj Though we would be discussing Clojure 1.1 on the Windows platform, these notes are appropriate for Linux/Mac users as well. If you notice any errors or typos, or have any comments or suggestions or good exercises I could include, please email me at satish.talim@gmail.com. Learn Clojure Online and for Free If you want to learn Clojure Programming for free, do join the batch at http://rubylearning.org/ RubyLearning is the first and only site in the world that teaches Ruby and Clojure Programming for free. Over 30 mentors help you through the learning process – 24x7. @ 2010 by Satish Talim Page 11
  • 12. Prepared exclusively for Clojure 101 Course participants INTRODUCTION TO CLOJURE What is Clojure? Clojure is a dynamically-typed, functional programming language that runs on the JVM (Java 5 or greater) and provides interoperability with Java. http://en.wikipedia.org/wiki/Functional_programming "A key characteristic of Clojure is that it is a functional language, which means that functions are the fundamental building-block for programs rather than instructions, as is the case in most other programming languages (known as imperative languages). In Clojure, functions are best thought of as more like their counterparts in mathematics – a function is simply an operation that takes a number of parameters (also called arguments), and returns a value. These functions always return the same result when passed the same arguments. Imperative languages perform complex tasks by executing large numbers of instructions, which sequentially modify a program state until a desired result is achieved. Functional languages achieve the same goal through nested function composition – passing the result of one function as a parameter to the next. By composing and chaining function calls, along with recursion (a function calling itself), a functional program can express any possible task that a computer is capable of performing. An entire program can itself be viewed as a single function, defined in terms of smaller functions. The nesting structure determines the computational flow, and all the data is handled through function parameters and return values." - From Practical Clojure. A major goal of Clojure is managing concurrency. Wikipedia has a great definition of concurrency: "Concurrency is a property of systems in which several computations are executing and overlapping in time, and potentially interacting with each other. The overlapping computations may be executing on multiple cores in the same chip, preemptively time-shared threads on the same processor, or executed on physically separated processors." The primary challenge of concurrency is managing access to a shared, mutable state. Clojure helps you write correct concurrent programs by emphasizing immutability. Clojure enforces isolating changes in mutable state as either atomic operation with atoms, within a transaction with refs, or asynchronously with agents. Additionally, there are no explicit locks in Clojure, so this common source of deadlock is removed. Michael Fogus, author of the book "The Joy of Clojure" says that - "Clojure was born out of creator Rich Hickey's desire to avoid many of the complications, both inherent and incidental, of developing concurrent applications using Java and C++. The Java Virtual Machine is an amazingly practical platform -- it is mature, fast, and widely deployed. It supports a variety of hardware and operating systems and has a staggering number of libraries and support tools @ 2010 by Satish Talim Page 12
  • 13. Prepared exclusively for Clojure 101 Course participants available, all of which Clojure can take advantage of, thus allowing prospective developers to avoid the costs of maintaining yet another infrastructure while leveraging existing libraries." The following shows briefly the release dates for various versions of Clojure: 1.2 is expected soon. 1.1 (the current version) released in Dec. 2009. 1.0 released in May 2009. Clojure was first released on October 16, 2007. @ 2010 by Satish Talim Page 13
  • 14. Prepared exclusively for Clojure 101 Course participants GETTING STARTED Labrepl Download and Installation (for MS Windows) What's Labrepl? Labrepl is an environment for exploring the Clojure language. It includes: a web application that presents a set of lab exercises with step-by-step instructions an interactive repl for working with the lab exercises up-to-date versions of Clojure, contrib, incanter, compojure and a bunch of other libraries to explore The Labrepl site mentions how one can use Labrepl on other operating systems. http://github.com/relevance/labrepl Downloading and Installing Labrepl (for MS Windows) Download and install Java version 6 - this is a pre-requisite. http://java.sun.com/javase/downloads/index.jsp Next, go to the Labrepl site and click on the "Download Source" button on the top of the page. A .zip file will get downloaded to your computer. Extract this .zip file to your c: drive. On my computer it created a folder c:relevance-labrepl-d6b9759. For Labrepl to work we shall also need Leiningen. http://github.com/technomancy/leiningen Leiningen is a build tool for Clojure. Installation of Leiningen on MS Windows is complicated, because automatic install isn't implemented yet. For MS Windows you need to download lein.bat script, and put it into the folder c:leiningen. http://github.com/technomancy/leiningen/raw/stable/bin/lein.bat Set your system environment variable "PATH" to include the folder c:leiningen. Create a sub-folder c:leiningenlib. @ 2010 by Satish Talim Page 14
  • 15. Prepared exclusively for Clojure 101 Course participants Next download leiningen-1.1.0-standalone.jar and copy it to the folder c:leiningenlib. http://github.com/downloads/technomancy/leiningen/leiningen-1.1.0- standalone.jar After this, download the clojure.jar package. A .zip file gets downloaded to your computer. From this .zip file extract clojure.jar and copy it to the c:leiningenlib folder. http://code.google.com/p/clojure/downloads/list Edit lines 14 and 15 of lein.bat to correct the path, namely: o set LEIN_JAR=c:leiningenlibleiningen-1.1.0-standalone.jar o set CLOJURE_JAR=c:leiningenlibclojure.jar Open a new command window and change folder to c:relevance-labrepl-d6b9759. Next type lein deps to install all the dependent libraries. This might take some time. Close the command window. Starting the REPL Interaction with Clojure is often performed at the REPL (Clojure read-eval-print loop). To start a REPL, open a new command window and change folder to c:relevance-labrepl- d6b9759. Next type: c:relevance-labrepl-d6b9759> scriptrepl This starts a new REPL session and you are presented with a simple user> prompt. It is at this point that REPL waits for user input. The user namespace is the REPL default, like the default package in Java. You should treat user as a scratch namespace for exploratory development. After user> type (println "Hello World") and press ENTER, as follows: user> (println "Hello World") Hello World nil user> @ 2010 by Satish Talim Page 15
  • 16. Prepared exclusively for Clojure 101 Course participants The second line above, Hello World, is the console output you requested. The third line, nil, is the return value of the call to Clojure's println (the funtion used to display something on the screen). For a list of all the functions available in the clojure.core API, see – http://richhickey.github.com/clojure/clojure.core-api.html. If you get your REPL into a state that confuses you, the simplest fix is to close the command window. Loading a file in the REPL If you have a block of code that is too large to conveniently type at the REPL, save the code into a file, and then load that file from the REPL. You can use an absolute path or a path relative to where you launched the REPL. Here's how you would load a file in your REPL: (load-file file-name) The load-file function sequentially reads and evaluates the set of forms (more on this later) contained in the file. A Clojure program is stored in a text file with the extension .clj. Let us load the file test.clj located in the folder c:userstalimmyprojectsrctest: (load-file "c:/users/talim/myproject/src/test/test.clj") ; => nil Clojure Box Download and Installation (for MS Windows) Note: If you have installed Labrepl then you can ignore this step. 1. Download and install Java version 6 - this is a pre-requisite. http://java.sun.com/javase/downloads/index.jsp 2. Download and install "Clojure Box". Clojure Box is an all-in-one installer for Clojure on Windows. You simply install and run this one thing, and you get a REPL (Clojure read-eval- print loop) and all the syntax highlighting and editing goodies from clojure-mode and Slime, plus all the power of Emacs under the hood. http://clojure.bighugh.com/ @ 2010 by Satish Talim Page 16
  • 17. Prepared exclusively for Clojure 101 Course participants Note: You can watch a video of "Install Clojure - ClojureBox". http://vimeo.com/9219062 Read the post install notes - http://bitbucket.org/shoover/clojure-box/src/tip/post- install.txt. Test if Clojure Box works Interaction with Clojure is often performed at the REPL. To test whether Clojure works, double-click on the "Clojure Box" icon on your desktop. This starts a new REPL session and you are presented with a simple user> prompt. It is at this point that REPL waits for user input. The user namespace is the REPL default, like the default package in Java. You should treat user as a scratch namespace for exploratory development. After user> type (println "Hello World") and press ENTER: user> (println "Hello World") Hello World nil user> The second line above, Hello World, is the console output you requested. The third line, nil, is the return value of the call to Clojure's println (the funtion used to display something on the screen). For a list of all the functions available in the clojure.core API, see – http://richhickey.github.com/clojure/clojure.core-api.html. If you get your REPL into a state that confuses you, the simplest fix is to kill the REPL with Ctrl-C. Loading a file in Clojure Box If you have a block of code that is too large to conveniently type at the REPL, save the code into a file, and then load that file from the REPL. You can use an absolute path or a path relative to where you launched the REPL. Here's how you would load a file in your REPL: @ 2010 by Satish Talim Page 17
  • 18. Prepared exclusively for Clojure 101 Course participants (load-file file-name) The load-file function sequentially reads and evaluates the set of forms (more on this later) contained in the file. A Clojure program is stored in a text file with the extension .clj. Let us load the file test.clj located in the folder c:userstalimmyprojectsrctest: (load-file "c:/users/talim/myproject/src/test/test.clj") ; => nil NetBeans/Enclojure Download and Installation (for MS Windows) Note: If you have installed Labrepl or Clojure Box then you can ignore this step. 1. Download and install Java version 6 - this is a pre-requisite. http://java.sun.com/javase/downloads/index.jsp 2. Download and install NetBeans 6.8 (Java SE option). http://netbeans.org/downloads/index.html 3. Download the latest Enclojure .nbm file. http://github.com/EricThorsen/enclojure/downloads In NetBeans go to Tools > Plugins. In the dialog click on Downloaded then click the "Add Plugins..." button. Navigate to the location where you saved the NBM file, select it and click the "Open" button. Highlight "Clojure Plugin" and click the "Install" button. Restart the NetBeans IDE. Next, navigate to Tools > Options > Clojure and at the bottom of the screen select clojure-1.1.0 for the Clojure platform. Click the "OK" button. Restart the NetBeans IDE. @ 2010 by Satish Talim Page 18
  • 19. Prepared exclusively for Clojure 101 Course participants To create a Clojure Project in NetBeans 1. Navigate to File > New Project... Select Categories Clojure and click the "Next" button. 2. I created a folder c:ClojureProjects on my hard disk. 3. I typed the following: Project Name: RL Default namespace: com.rl.hello Project location: c:ClojureProjects 4. Click the "Finish" button. To start the REPL in NetBeans 1. Right click on the newly created project namely RL, which you should be seeing in the Projects window. 2. Select "Start Project REPL" in the window that pops up. Anatomy of the Enclojure REPL Panel See: http://www.enclojure.org/Anatomy+of+the+Enclojure+Repl+Panel Note: You can watch a video of "Install Clojure - NetBeans". http://vimeo.com/9220148 Syntax Clojure is a Lisp dialect and has a syntax that uses parentheses and prefix notation. For example, in Java one might write foo(a, b, c), whereas in a Lisp dialect this becomes (foo a, b, c). Since the commas are whitespace and Clojure ignores them, it can be simplified further to (foo a b c). Many text editors and IDEs highlight matching parentheses, so it isn't necessary to count them in order to ensure they are balanced. Clojure is case-sensitive. Comments Open a new REPL and try out whatever we discuss, from now on. @ 2010 by Satish Talim Page 19
  • 20. Prepared exclusively for Clojure 101 Course participants There are two ways in which you can comment in Clojure. A line comment is: ; This is a single line Clojure comment For block comments: (comment text) It should be noted that the block comment form above does have a return value, namely nil. So you can't just "comment out" a piece of your code with it, because it still leaves a trace. This form is sometimes used at the end of a source code file to demonstrate usage of an API. For example, the Clojure inspector library ends with the following comment, demonstrating the use of the inspector: (comment (load-file "src/inspector.clj" ) (refer 'inspector) (inspect-tree {:a 1 :b 2 :c [1 2 3 {:d 4 :e 5 :f [6 7 8]}]}) (inspect-table [[1 2 3][4 5 6][7 8 9][10 11 12]]) ) Clojure Coding Guidelines & Naming Convention 1. Use two spaces for indentation. 2. Make your names for functions, vars as descriptive as possible, without being overly verbose. 3. Use lower-case letters for names. 4. The names of predicate functions (returning a truthy (everything not nil or false) or falsy (false and nil) should typically end with a question mark (?). 5. End the name of a function in an exclamation mark (!) if it is destructive. The obvious exceptions to the guidelines above are when generating Java code, which requires that Java naming conventions be observed. @ 2010 by Satish Talim Page 20
  • 21. Prepared exclusively for Clojure 101 Course participants For more details please see the Clojure Library Coding Standards. http://www.assembla.com/wiki/show/clojure/Clojure_Library_Coding_Standards The naming convention in Clojure is to use all lowercase with hyphens separating words in multi-word names, unlike the Java convention of using camelcase. An example: (function-name arg1 arg2 arg3) Forms Clojure code is composed of Clojure data. When you run a Clojure program, a part of Clojure called the reader reads the text of the program in chunks called forms and translates them into Clojure data structures. Clojure then compiles and executes the data structures. A Clojure form is basically just an expression. It's any piece of code that evaluates down to a single value. The Clojure forms are: symbols, literals (i.e. booleans, nil, numbers, characters, strings, keywords), lists, vectors, maps and sets. Symbols Symbols are used to name things. Symbols name all sorts of things in Clojure: Functions like str and concat Clojure does not have operators. Characters like + - * / are just functions Java classes like java.lang.String and java.util.Random Namespaces like clojure.core and Java packages like java.lang Data structures and references. Symbols cannot start with a number and can consist of alphanumeric characters, plus +, -, *, /, !, ?, ., and _. You can call a function through a symbol such as println: (println "Hello Clojure participants") ; => Hello Clojure participants @ 2010 by Satish Talim Page 21
  • 22. Prepared exclusively for Clojure 101 Course participants Rather than calling a function through a symbol, you might choose just to retrieve the function itself. The literal representation of a function at the REPL is just a mangled name: println Sometimes you want to refer to the symbol itself, without retrieving whatever it refers to. To do this, you can quote the symbol: (quote println) ; => println Quoting is so common that that there is a sugared form: simply put a single quote in front of any symbol to prevent that form from being evaluated: 'println ; => println Vars and Bindings The special form (these are forms evaluated in a special way) def creates a var. If the var did not already exist and no initial value is supplied, the var is unbound. In the code below, x is a symbol which is used to identify the var in the future. At this point, x has no "value", and so we can't refer to it: (def x) ; => #'user/x x ; => java.lang.IllegalStateException: var user/x is unbound. If called with an additional parameter it creates a root binding or rebinds the var in case it was already bound. This binding is like an "invisible" link between the var and the value. For example, the following def creates a var named user/my-var in the namespace user: (def my-var 10) ; => #'user/my-var The symbol user/my-var refers to a var that is bound to the value 10. The initial value of a var is called its root binding. Clojure provides bindings which are like constants in other languages, which are not intended to be changed after a value is assigned. Other threads can then override that binding temporarily. Threads which do not have a thread local binding will inherit the root binding. There are global bindings, thread-local bindings, bindings that are local to a function and bindings that are local to a given form. @ 2010 by Satish Talim Page 22
  • 23. Prepared exclusively for Clojure 101 Course participants The def special form creates a global binding and optionally gives it a "root value" that is visible in all threads unless a thread-local value is assigned. In Clojure, the object that your var is referring to can't change. If you want your var to refer to a different value, you have to rebind it to a new object, a new value. Although vars can be rebound, it is generally not done in a program except to create thread-local bindings. Literals Booleans and nil Clojure’s rules for booleans (true and false) are easy to understand: 1. true is true, and false is false. 2. In addition to false, nil (meaning 'nothing/no-value'- represents Java null) also evaluates to false when used in a boolean context. 3. Other than false and nil, everything else evaluates to true in a boolean context. Numbers A number consists of only the digits 0-9, a decimal point '.', a sign ('+' or '-'), and an optional 'e' for numbers written in exponential notation. In addition to these elements, numbers in Clojure can take either octal or hexadecimal form and also include an optional 'M' (this is used to explicitly create a BigDecimal). Clojure supports the following numeric types: integer, floating point, ratio. Integers comprise the whole number set, both positive and negative. That is, any number starting with an optional sign or digit followed exclusively by digits is considered and stored as an integer. Integers in Clojure can theoretically take an infinitely large value, although in practice the size is limited by the memory available. @ 2010 by Satish Talim Page 23
  • 24. Prepared exclusively for Clojure 101 Course participants Floating point numbers are of the form of some number of digits, a decimal point, followed by some number of digits. However, floating point numbers can also take an exponential form where a significant part is followed by an exponent part separated by a lower or uppercase 'E'. 0x7F ; => hexadecimal number whose value is 127 0177 ; => octal number whose value is 127 11.7e-3 ; => 0.0117 (+ 1 2 3 4) ; => 10 (/ 22 7) ; => 22/7 200/5 ; => 40 In the code above, we first use the + function to add the numbers 1, 2, 3 and 4. The result of (/ 22 7) is surprising as Clojure has a built in clojure.lang.Ratio type. Using ratios help avoid inaccuracies in long computations. Ratios are represented by an integer numerator and denominator. Also observe that the ratio 200 / 5 will resolve to the integer 40. Lets first try a computation of (1/5 * 5/1) as floating point. Later we try the same with Ratio. (def x (/ 1.0 5.0)) (def y (/ 5.0 1.0)) (* x y) ; => 1.0 (def p (* x x x x x x x x x x)) (def q (* y y y y y y y y y y)) (* p q) ; => 1.0000000000000004 The value of (* p q) above is 1.0000000000000004 instead of 1 which is what we want. This is due to the inaccuracies of x and y multiplying as we create p and q. You really don't want such calculations happening in your financial transactions! The same done with ratios below: (def x (/ 1 5)) (def y (/ 5 1)) (* x y) ; => 1 (def p (* x x x x x x x x x x)) (def q (* y y y y y y y y y y)) (* p q) ; => 1 Using a floating point literal instead, we get: (/ 22.0 7) ; => 3.142857142857143 @ 2010 by Satish Talim Page 24
  • 25. Prepared exclusively for Clojure 101 Course participants Arbitrary-precision arithmetic In Clojure, we can do arbitrary-precision arithmetic - a technique whereby calculations are performed on numbers whose digits of precision are limited only by the available memory of the host system. Clojure relies on Java's BigDecimal class for arbitrary-precision decimal numbers and on Java's BigInteger class for arbitrary-precision integers. http://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic If you are doing arbitrary-precision math, append M to a number to create a BigDecimal literal: (+ 1 (/ 0.00001 1000000000000000000)) ; => 1.0 (+ 1 (/ 0.00001M 1000000000000000000)) ; => 1.00000000000000000000001M Clojure objects are Java objects and you can use Java's Reflection API methods such as class, ancestors, and instance? to reflect against the underlying Java object model. (class (+ 1 (/ 0.00001M 1000000000000000000))) ; => java.math.BigDecimal Clojure's approach to arbitrary-sized integers is simple: just don't worry about it. Clojure will automatically upgrade to Long or BigInteger when you need it. Try creating some small and large integers, and then inspect their class: (class (* 100 100 100)) ; => java.lang.Integer (class (* 9000 9000 9000)) ; => java.lang.Long (class (* 9000 9000 9000 9000 9000 9000 9000 9000)) ; => java.math.BigInteger format Round off a number to say 2 decimal places: (format "%.2f" 1.2345) ; => "1.23" Characters and Strings Clojure character literals are preceded by a backslash. Their literal syntax is {letter}, where letter can be a letter or the name of a character: backspace, form-feed, newline, return, space, or tab. These yield the corresponding characters. Clojure strings are Java strings. They are immutable, and have access to all the underlying Java methods. They are delimited by double quotes ("), and they can span multiple lines. @ 2010 by Satish Talim Page 25
  • 26. Prepared exclusively for Clojure 101 Course participants Strings are sequences of characters. The function concat returns a list of character literals, of the elements in the supplied strings: (concat "Hello" " World") ; => (H e l l o space W o r l d) Clojure's str is a function call that concatenates an arbitrary list of arguments into a string: (str h e l l o space w o r l d) ; => "hello world" (str "Hello" " " "World") ; => "Hello World" Standard Java escape characters are supported. If you want to put a double quote inside a string then you have to escape the double quote. The backslash is the escape character: (println "She replied: "Hello" to my greetings.") ; => She replied: "Hello" to my greetings. Keywords A keyword is like a symbol, except that keywords begin with a colon (:). Keywords resolve to themselves: :foo ; => :foo The fact that keywords resolve to themselves makes keywords useful as keys. Exercises Exercise 1 Write a Clojure program that displays how old I am, if I am 979000000 seconds old. Sample solution: (println "You are" (/ 979000000 60.0 60 24 365) "years old") ; => You are 31.04388635210553 years old ; Note that println automatically added a space between its arguments We can improve upon the above program. It's always better to perform the calculation using exact numbers and then coerce the result if needed (we use float in the example below). This is an advantage which Clojure offers when compared to other languages; you can perform @ 2010 by Satish Talim Page 26
  • 27. Prepared exclusively for Clojure 101 Course participants calculations with exact numbers instead of floating point approximations. A better solution would be: (println "You are" (float (/ 979000000 60 60 24 365)) "years old") ; => You are 31.043886 years old Exercise 2 Write a Clojure program that tells you how many minutes there are in a year (do not bother right now about leap years etc.). Sample solution: (println "There are" (* 60 24 365) "minutes in a year") ; => There are 525600 minutes in a year @ 2010 by Satish Talim Page 27
  • 28. Prepared exclusively for Clojure 101 Course participants CHARGING AHEAD A Quick look at Collections Clojure provides the collection types list, vector, set and map. The Clojure collection types are immutable, heterogeneous and persistent. By immutable it means that their contents cannot be changed. By heterogeneous it means that they can hold any kind of object. By persistent it means that when a new version of a collection is created by adding or removing something from it, the new version shares structure with the old one. The old version will be accessible only when we hold a reference to its head otherwise it will be garbage collected. Lists Lists are written with parenthesis. Lists are the traditional lisp singly linked lists. Lists can contain items of any type, including other collections: ; Empty list () ; => () (class ()) ; => clojure.lang.PersistentList$EmptyList '(a b c) ; => (a b c) (class '(a b c)) ; => clojure.lang.PersistentList A list is "just data," but it is also used to call functions. They are ideal when new items will be added to or removed from the front. Lists are not efficient for finding items by index. An example of a list whose first item names a Clojure function: (+ 1 2) In Clojure, data and code have the same representation. (a b c) is a call to a function named a with arguments b and c. To make this data instead of code, the list needs to be quoted. '(a b c) or (quote (a b c)) is a list of the values a, b and c. It may be good to note that lists are singly linked lists. @ 2010 by Satish Talim Page 28
  • 29. Prepared exclusively for Clojure 101 Course participants Vectors Vectors are essentially like dynamically-sized arrays. Vectors store a series of values like lists do and can be used like lists, except that they can be indexed by integers. Vectors are written with square brackets: [1 2 3] ; => [1 2 3] (class [1 2 3]) ; => clojure.lang.PersistentVector [ ] ; => [ ] (class [ ]) ; => clojure.lang.PersistentVector Vectors are ideal when new items will be added to or removed from the back. Vectors are efficient for finding or changing items by index i.e. vectors are functions of their indices: ; retrieve an element by its index (["hello" "world" 1 2 3] 1) ; => "world" Note: Unless the list characteristic of being more efficient at adding to or removing from the front is significant for a given use, vectors are typically preferred over lists. This is mainly due to the vector syntax of [...] being a bit more appealing than the list syntax of '(...). It doesn't have the possibility of being confused with a call to a function, macro or special form. Sets Sets are collections of unique items. Sets are zero or more forms enclosed in braces preceded by #. The #{} reader macro is only for hash sets: #{ } ; => #{ } (class #{ }) ; => clojure.lang.PersistentHashSet #{:a :b :c} ; => #{:a :b :c} Sets are preferred over lists and vectors when duplicates are not allowed and items do not need to be maintained in the order in which they were added. Clojure supports two kinds of sets, unsorted and sorted. Hash sets are generally preferred over sorted sets as they are much faster. Sorted sets are important when keeping things sorted is very important. Here are some more ways to create a set: (sorted-set "Mandy" "Anita" "Rich") ; #{"Anita" "Mandy" "Rich"} (hash-set "Mandy" "Anita" "Rich") ; #{"Anita" "Mandy" "Rich"} ; duplicates are removed (hash-set "Rich" "Mandy" "Anita" "Rich") ; #{"Anita" "Mandy" "Rich"} @ 2010 by Satish Talim Page 29
  • 30. Prepared exclusively for Clojure 101 Course participants Maps Maps are zero or more key/value pairs where both can be any kind of object and enclosed in braces. Maps store unique keys and one value per key. Often keywords are used for map keys: { } ; => { } (class { }) ; => clojure.lang.PersistentArrayMap {:Ruby "Matz" :Clojure "Hickey"} ; => {:Ruby "Matz" :Clojure "Hickey"} You can use a map directly, it is not necessary to bind it to a name: (:a {:a 1, :b 2}) ; => 1 We can use def to save the map into a Clojure var: (def inventors {:Ruby "Matz" :Clojure "Hickey"}) Commas are considered whitespace, and can be used to organize the pairs: (def inventors {:Ruby "Matz", :Clojure "Hickey"}) Maps are functions. If you pass a key to a map, it will return that key’s value, or it will return nil if the key is not found: (:Clojure inventors) ; => Hickey (inventors :Java) ; => nil The keys function returns a sequence of the map's keys: ; Usage: (keys map) (keys inventors) ; => (:Ruby :Clojure) The vals function returns a sequence of the map's values: ; Usage: (vals map) (vals inventors) ; => ("Matz" "Hickey") @ 2010 by Satish Talim Page 30
  • 31. Prepared exclusively for Clojure 101 Course participants Some functions on collections There are many core functions that operate on all kinds of collections; far too many to describe here. A small subset of them is described next, mostly using vectors and sometimes lists. count function The count function returns the number of items in any collection. (count [22 "green" false]) ; => 3 ; empty collections correctly return 0 (count '()) ; => 0 reverse function The reverse function returns a sequence of the items in the collection in reverse order. (reverse [2 42 72]) ; => (72 42 2) (reverse '(2 42 72)) ; => (72 42 2) ; strings are collections too (reverse "hello") ; => (o l l e h) apply function The apply function returns the result of a given function when all the items in a given collection are used as arguments. (apply - [34 23 9]) ; => 2 map function (map f coll) map takes a source collection coll and a function f, and it returns a new sequence by invoking f on each element in the coll. (map * [1 2 3 4] [1 2 3 4]) ; => (1 4 9 16) @ 2010 by Satish Talim Page 31
  • 32. Prepared exclusively for Clojure 101 Course participants Sequences A sequential collection is one that holds a series of values without reordering them. A sequence is a sequential collection that represents a series of values that may or may not exist yet. They may be values from a concrete collection, or values that are computed as necessary. A sequence may be empty. Sequences include Java collections, Clojure-specific collections, strings, streams, directory structures and XML trees. Because so many things are sequences, the sequence library is very powerful. Remember that the sequence library can be used with all collections (lists, vectors, sets, maps ...). Important: Most Clojure sequences are lazy: they generate elements only when they are actually needed. Clojure sequences are immutable: they never change. seq The seq function turns any core collections into something called a seq i.e. the seq function will return a seq on any seq-able collection (coll): (seq coll) seq will return nil if its coll is empty or nil. An example: (seq [1 2 3]) ; => (1 2 3) (seq [ ]) ; => nil first You can get the first item in a sequence: (first aseq) first returns nil if its argument is empty or nil. @ 2010 by Satish Talim Page 32
  • 33. Prepared exclusively for Clojure 101 Course participants An example: (first [34 23 15]) ; => 34 (first [ ]) ; => nil rest You can get everything after the first item, in other words, the rest of a sequence: (rest aseq) rest returns an empty seq (not nil) if there are no more items. An example: (rest [34 23 15]) ; => (23 15) (rest [ ]) ; => () (class (rest [ ])) ; => clojure.lang.PersistentList$EmptyList cons You can construct a new sequence by adding an item to the front of an existing sequence: (cons elem aseq) An example: (cons 1 [2 3 4]) ; => (1 2 3 4) Under the hood, first, rest and cons are declared in a Java interface clojure.lang.ISeq. next The next function will return the seq of items after the first: (next aseq) (next aseq) is equivalent to (seq (rest aseq)). @ 2010 by Satish Talim Page 33
  • 34. Prepared exclusively for Clojure 101 Course participants An example: (next [1 2 3 4]) ; => (2 3 4) conj, into (conj coll element & elements) (into to-coll from-coll) conj adds one or more elements to a collection, and into adds all the items in one collection to another. For lists, conj and into add to the front: (conj '(10 20 30) :a) ; => (:a 10 20 30) (into '(10 20 30) '(:a :b :c)) ; => (:c :b :a 10 20 30) For vectors, conj and into add elements to the back: (conj [10 20 30] :a) ; => [10 20 30 :a] (into [10 20 30] [:a :b :c]) ; => [10 20 30 :a :b :c] range range produces a sequence from a start to an end, incrementing by step each time. Ranges include their start, but not their end. If you do not specify them, start defaults to zero, and step defaults to 1. (range 10 20 2) ; => (10 12 14 16 18) repeat The repeat function repeats an element p n times: (repeat 5 "p") ; => ("p" "p" "p" "p" "p") iterate, take (iterate f x) iterate begins with a value x and continues forever, applying a function f to each value to calculate the next. @ 2010 by Satish Talim Page 34
  • 35. Prepared exclusively for Clojure 101 Course participants If you begin with 1 and iterate with inc, you can generate the whole numbers: (take 10 (iterate inc 1)) ; => (1 2 3 4 5 6 7 8 9 10) Since the sequence is infinite, you need another new function to help you view the sequence from the REPL. (take n sequence) take returns a lazy sequence of the first n items from a collection and provides one way to create a finite view onto an infinite collection. The following example creates a lazy seq of all natural numbers: <pre class="brush: clojure"> An usage example: (take 5 natural-numbers) ; => (0 1 2 3 4) concat The concat function can be used for plain concatenation of any collection: (concat [22 "green" false] [33 44]) ; => (22 "green" false 33 44) ; the two collections can be of different types (concat #{22 "green" false} '(33 44)) ; => ("green" false 22 33 44) Flow Control @ 2010 by Satish Talim Page 35
  • 36. Prepared exclusively for Clojure 101 Course participants if, if-not Clojure’s if evaluates its first argument. If the argument is logically true, it returns the result of evaluating its second argument. If you want to define a result for the "else" part of if, add it as a third argument (but this is optional): (println (if (< 34 100) "yes" )) ; => yes (println (if 0 "Zero is true" "Zero is false")) ; => Zero is true If the first argument to if is logically false and you didn't specify an else form, it returns nil: (if (< 50000 100) "yes" ) ; => nil The if-not macro does the inverse of what the if special form does. The general structure of this macro is: (if-not test consequent alternative?) Here, if the test is false, the consequent is evaluated, else if it is true and the alternative is provided, it is evaluated instead. cond, condp cond is like the case statement of Clojure. The general form looks like the following: (cond & clauses) Here's an example: @ 2010 by Satish Talim Page 36
  • 37. Prepared exclusively for Clojure 101 Course participants (def x 10) (cond (< x 0) (println "Negative!") (= x 0) (println "Zero!")) ; => nil (cond (< x 0) (println "Negative!") (= x 0) (println "Zero!") :default (println "Positive!")) ; => Positive! As you can see, the clauses are a pair of expressions, each of the form test consequent. Each test expression is evaluated in sequence, and when one returns true, the associated consequent is evaluated and returned. If none return true, nil is returned. If a :default is provided, the associated consequent is evaluated and returned instead. The general form of condp looks like the following: (condp pred expr & clauses) The condp macro is similar to a case statement in other languages. It takes a two parameter predicate (this is mostly = or instance?) and an expression to act as its second argument. After those it takes any number of value/result expression pairs that are evaluated in order. If the predicate evaluates to true when one of the values is used as its first argument then the corresponding result is returned. An optional final argument is the result to be returned if no given value causes the predicate to evaluate to true. If this is omitted and no given value causes the predicate to evaluate to true then an IllegalArgumentException is thrown: (condp = 1 1 "Clojure" 2 "Ruby" 3 "Java" "Sorry, no match") ; => "Clojure" (condp = 5 1 "Clojure" 2 "Ruby" 3 "Java" "Sorry, no match") ; => "Sorry, no match" when, when-not @ 2010 by Satish Talim Page 37
  • 38. Prepared exclusively for Clojure 101 Course participants The when form is similar to the if form. The differences are that there is no "else" condition, and more than one expression can be added to the when form for evaluation when the condition is true. (when true "do-this-first" "then-that" "finally this") ; => "finally this" when-not is the opposite of when, in that it evaluates its body if the test returns false. (when-not true "do-this-first" "then-that" "finally this") ; => nil (when-not false "do-this-first" "then-that" "finally this") ; => "finally this" do The do form is used to execute a number of operations in sequence. Clojure provides the println form for writing to standard output. In order to use println within an expression whose return value we care about, we need to put it in a do expression: (do (println "Hello.") (+ 2 2)) Hello. 4 (do (println "Hello.") (println "Hello again.") (+ 2 2)) Hello. Hello again. 4 The do operation executes each expression in sequence and returns the result of the last expression. do is useful when you want to include a sequence of actions in a position where only a single form is expected, e.g. for having various statements in a branch of an if. Here's a contrived example: (if (odd? 3) (println "First true form") (println "Second true form (will not print)")) ; => First true form (if (odd? 3) (do (println "First true form") (println "Second true form (will print)"))) ; => First true form ; => Second true form (will print) @ 2010 by Satish Talim Page 38
  • 39. Prepared exclusively for Clojure 101 Course participants if only accepts one form as if and else branch, so if you want to have several statements in either, you'll have to wrap them in a do. In the first statement above, the second true from will not print, since Clojure sees it as the else-branch. In the second it prints, because do is considered one form. Defining Functions The defn macro defines a function. Its arguments are the function name, an optional documentation string, the parameter list (specified with a vector that can be empty) and the function body. The result of the last expression in the body is returned. Every function returns a value, but it may be nil. (defn my-function "returns a String" [name] (str "Goodbye, " name)) ; concatenation (println (my-function "Satish")) ; => Goodbye, Satish Function definitions must appear before their first use. Sometimes this isn't possible due to a set of functions that invoke each other. The declare special form takes any number of function names and creates forward declarations that resolve these cases: (declare function-names) defn- works just like defn but functions defined with the defn- macro are private and are hardly secure. This means they are only visible in the namespace in which they are defined. It is trivial to access a private var and as such, defn- should not be used as a security measure. You could use defn- to create some helper functions that shouldn't be exposed outside the namespace. user> (ns sqr) (defn- sq [x] (* x x)) (defn sum-of-squares [p q] (+ (sq p) (sq q))) #'sqr/sum-of-squares sqr> (sum-of-squares 4 5) ; => 41 sqr> (sq 5) java.lang.Exception: Unable to resolve symbol: sq in this context If you call a function with an incorrect number of arguments, Clojure will throw an IllegalArgumentException. @ 2010 by Satish Talim Page 39
  • 40. Prepared exclusively for Clojure 101 Course participants Functions can take a variable number of parameters (note that there are no commas delimiting the function parameters). Optional parameters must appear at the end. They are gathered into a list by adding an ampersand and a name for the list at the end of the parameter list: (defn dating [person & who-all] (println person "are dating" (count who-all) "people." )) (dating "You" "1" "2" "3") ; => You are dating 3 people. ; dating function called with only the mandatory parameter (dating "You") ; => You are dating 0 people. Clojure functions are "first-class" functions i.e. Clojure functions can be stored, passed and returned just as any other piece of data within that language. Thus, Clojure functions can be stored in vars, held in lists and other collection types, be passed as arguments to and even returned as the result of other functions. Function definitions can contain more than one parameter list and corresponding body. Each parameter list must contain a different number of parameters. This supports overloading functions. Note that overloading of Clojure functions are based on arity (arity refers to the differences in the argument count that a function will accept) and not on type: (defn greet ([] (greet " world")) ([name] (str "Hello " name))) Anonymous functions have no name. These are often passed as arguments to a named function. When an anonymous function is defined using the fn special form, the body can contain any number of expressions. ((fn [x] (+ x 1)) 9) ; => 10 Functions can be bound to a symbol: (def plus-one (fn [x] (+ x 1))) (plus-one 9) ; => 10 An anonymous function can also be defined in the short way using #(...). The parameters are named %1, %2, and so on. You can also use % for the first parameter. (#(apply str %1 %2) "Hello" " World") ; => Hello World @ 2010 by Satish Talim Page 40
  • 41. Prepared exclusively for Clojure 101 Course participants Finally remember that, Clojure function calls are Java method calls. Exercise 1 Write a method called convert that takes one argument which is a temperature in degrees Fahrenheit. This method should return the temperature in degrees Celsius. Sample Solution: (defn convert [fahr] (float (* (- fahr 32) 5/9))) ; Note the use of Clojure Ratio (println ( str "The temperature in Celcius = " (convert 75))) ; => The temperature in Celcius = 23.88889 Exercise 2 Write a method leap-year? It should have as an argument a year value, check whether it's a leap year and then return true or false. A leap year is every 4 years, but not every 100 years, then again every 400 years. Sample Solution: (defn leap-year? [input-year] (or (and (= (rem input-year 4) 0) (> (rem input-year 100) 0)) (= (rem input-year 400) 0))) (leap-year? 2100) ; => false Note: (= x y) - Here = is the equality function and returns true if x equals y, false if not. (rem num div) - Here rem gives us the remainder of dividing numerator by denominator. and macro evaluates exprs one at a time, from left to right. If a form returns logical false (nil or false), "and" returns that value and doesn't evaluate any of the other expressions, otherwise it returns the value of the last expr. (and) returns true. or macro evaluates exprs one at a time, from left to right. If a form returns a logical true value, "or" returns that value and doesn't evaluate any of the other expressions, otherwise it returns the value of the last expression. (or) returns nil. @ 2010 by Satish Talim Page 41
  • 42. Prepared exclusively for Clojure 101 Course participants Exercise 3 Create a divides? predicate that takes a dividend and a divisor, and returns true if divisor evenly divides the dividend: Sample Solution: (defn divides? "Does divisor divide dividend evenly?" [dividend divisor] (zero? (rem dividend divisor))) Note: zero? returns true if the argument to zero? is zero, else false. @ 2010 by Satish Talim Page 42
  • 43. Prepared exclusively for Clojure 101 Course participants Documentation Using doc Nearly all the forms in Clojure have built-in documentation. If you want to read the doc at the REPL, you can just ask for the function’s doc string: user > (doc first) ------------------------- clojure/first ([coll]) Returns the first item in the collection. Calls seq on its argument. If coll is nil, returns nil. nil user > doc will also tell you if a form is implemented as a macro: user > (doc and) ------------------------- clojure.core/and ([] [x] [x & next]) Macro Evaluates exprs one at a time, from left to right. If a form returns logical false (nil or false), and returns that value and doesn't evaluate any of the other expressions, otherwise it returns the value of the last expr. (and) returns true. nil user > find-doc The find-doc function will search for anything whose doc output matches a regular expression or string you pass in. Example: (find-doc "list") Regular expressions in Clojure look like strings prepended by an #. Use a regular expression to find all the find- functions: (find-doc #"find-w+") @ 2010 by Satish Talim Page 43
  • 44. Prepared exclusively for Clojure 101 Course participants Documenting a function Every function can have a doc description (similar to Javadoc) attached to it, like: user > (defn plus-one "Returns a number one greater than x" [x] (+ x 1)) #'user/plus-one user > (doc plus-one) ------------------------- user/plus-one ([x]) Returns a number one greater than x nil user > Clojure API Clojure’s complete API is documented online at http://clojure.org/api. The right sidebar links to all functions and macros by name, and the left sidebar links to a set of overview articles on various Clojure features. @ 2010 by Satish Talim Page 44
  • 45. Prepared exclusively for Clojure 101 Course participants CLOJURE AND JAVA Working with Java Note: This section requires you to have knowledge of the Java programming language. Importing multiple classes Note: Clojure programs can use all Java classes and interfaces. As in Java, classes in the java.lang package can be used without importing them. Java classes in other packages can be used by either specifying their package when referencing them or using the import function (use import to refer to Java classes in the current namespace). (import 'java.util.Random) import also takes a variable number of lists, with the first part of each list being a package name and the rest being names to import from that package: (import '(java.util Random Locale) '(java.text MessageFormat)) Create a Java object Assuming that you have used the import form as shown above, we can create a Java object of Random as follows: (Random.) ; note the . Note the existence of the (new) special form. The (ClassName.) form is simply a macro for (new ClassName): (macroexpand '(Date.)) ; => (new Date) Note: The macroexpand function returns a macro form's expansion. http://richhickey.github.com/clojure/clojure.core-api.html#clojure.core/macroexpand @ 2010 by Satish Talim Page 45
  • 46. Prepared exclusively for Clojure 101 Course participants To use a Random, you will need to save it away somewhere. For now, simply use def to save the Random into a Clojure var: (import '(java.util Random)) (def rnd (Random.)) Accessing methods Random also has a nextInt( ) method that takes an argument. You can call it by: (import '(java.util Random)) (def rnd (Random.)) (.nextInt rnd 10) Also, note that (.methodName obj) is a macro for (. obj methodName): (macroexpand '(.toString (Date.))) ; => (. (Date.) toString) If you can't remember all the methods in the Random class, you can pass either a class or an instance to javadoc: (javadoc java.util.Random) ..chains The (..) macro chains together multiple member accesses by making each result the this object for the next member access in the chain. Thus looking up an object’s code URL becomes the following: (.. '(1 2) getClass getProtectionDomain getCodeSource getLocation) Note: The .. reads left to right, like Java. The .. macro is great if the result of each operation is an input to the next. It is possible to pass arguments in the intermediate function calls. @ 2010 by Satish Talim Page 46
  • 47. Prepared exclusively for Clojure 101 Course participants doto Sometimes you don’t care about the results of method calls and simply want to make several calls on the same object. The doto macro makes it easy to make several calls on the same object. For example, use doto to set multiple system properties: (doto (System/getProperties) (.setProperty "name" "Stuart") (.setProperty "favoriteColor" "blue")) doto returns the object at the end. This is very useful for Java Swing classes: (doto (javax.swing.JPanel.) (.setEnabled false) (.setToolTipText "Not available")) ; => #<JPanel javax.swing.JPanel[,0,0,0x0,invalid,disabled,layout=java.awt.FlowLayout,alignmentX=0.0 ,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=]> Accessing static fields (Math/PI) ; => 3.141592653589793 (System/getProperty "java.home") ; => "C:Program FilesJavajdk1.6.0_20jre" Accessing static methods For static methods, you can use (Classname/membername): (System/currentTimeMillis) ; => 1272362112453 -> macro (import [java.util Date Random]) (Date. (long (.nextInt (Random.)))) ; => #<Date Sat Jan 10 06:37:47 IST 1970> In the above code, starting from the inside, you: 1. get a new Random 2. get the next random integer 3. cast it to a long 4. pass the long to the Date constructor @ 2010 by Satish Talim Page 47
  • 48. Prepared exclusively for Clojure 101 Course participants The above is a bit confusing for beginners new to Clojure. You don't have to write inside-out code in Clojure. The -> macro takes its first form, and passes it as the first argument to its next form. The result then becomes the first argument of the next form, and so on. It is easier to read than to describe: (import [java.util Date Random]) (-> (Random.) (.nextInt) (long) (Date.)) ; => #<Date Sat Jan 10 06:37:47 IST 1970> Exception handling All exceptions thrown by Clojure code are runtime exceptions. Java methods invoked from Clojure code can still throw checked exceptions. In Clojure, you are not forced to deal with checked exceptions. You do not have to catch them or declare that you throw them. The try, catch, finally and throw special forms provide functionality similar to their Java counterparts. Let's look at an example: (/ 1 0) ; => java.lang.ArithmeticException: Divide by zero In the above case we see an java.lang.ArithmeticException being thrown. This is a runtime exception which is thrown by the underlying JVM. The following shows how runtime exceptions like java.lang.ArithmeticException can be handled: (try (/ 1 0) (catch Exception e (prn "in catch")) (finally (prn "in finally"))) "in catch" "in finally" nil Note: The pr and prn functions prints the object(s) to the output stream that is the current value of *out*. pr prints the object(s), separated by spaces if there is more than one. By default, pr and prn print in a way that objects can be read by the reader. prn is the same as pr followed by (newline). @ 2010 by Satish Talim Page 48
  • 49. Prepared exclusively for Clojure 101 Course participants Some More Examples (.toUpperCase "hello") ; => HELLO (.length "hello") ; => 5 In the next example, let's write a parse helper function: (defn parse [s] (try (Double/parseDouble (.trim s)) (catch NumberFormatException e nil))) (parse "22") ; => 22.0 (parse " 23.45 ") ; => 23.45 (parse "asas") ; => nil In the following example, the display helper function takes a number, rounds it to the nearest Integer (because Integers are prettier), and returns a String: (defn display [n] (str (Math/round (float n)))) (display 22.5) ; => "23" (display 22/7) ; => "3" Source for a function You can use Clojure to tell you the source for a function. To use this functionality, you’ll need to import the repl-utils library: user> (use 'clojure.contrib.repl-utils) nil user> (source println) (defn println "Same as print followed by (newline)" [& more] (binding [*print-readably* nil] (apply prn more))) nil user> Inspector One useful utility built into Clojure is the ability to pop up a Swing app that can inspect a data structure. @ 2010 by Satish Talim Page 49
  • 50. Prepared exclusively for Clojure 101 Course participants http://richhickey.github.com/clojure/clojure.inspector-api.html To start using it, type: (use 'clojure.inspector) ; => nil You can use the generic inspect function to look at arbitrary objects: (inspect (System/getProperties)) @ 2010 by Satish Talim Page 50
  • 51. Prepared exclusively for Clojure 101 Course participants DIVING INTO CLOJURE Namespaces Clojure partitions things that are named by symbols into namespaces. There is always a current default namespace, initially set to "user", and it is stored in the special symbol *ns*. The "user" namespace provides access to all the symbols in the clojure.core namespace. Clojure respects Java naming conventions for directories and files, but Lisp naming conventions for namespace names. So a Clojure namespace com.my-app.utils would live in a path named com/my_app/utils.clj. Note especially the underscore/hyphen distinction. in-ns function The default namespace can be changed by the in-ns function. Let's create a "notes" namespace: (in-ns 'notes) ; => #<Namespace notes> Now you are in the "notes" namespace, and anything you def or defn will belong to "notes". When you create a new namespace with in-ns, the java.lang package is automatically available to you. ns The general form of the ns macro is: (ns name & references) The default namespace can be changed by the ns macro. The name, as mentioned above, is the name of the namespace being made current. If it doesn't already exist, it gets created. The references that follows the name are optional, and can be one or more of the following – use, require, import, load, gen-class, or load. The ns macro will create a new namespace that contains mappings for the classnames in java.lang and for the functions in clojure.core. Note: In order to access items that are not in the default namespace they must be namespace-qualified. This is done by preceding a name with a namespace name and a slash (whereas Java package names are separated from a class name with a period). Use “use” to @ 2010 by Satish Talim Page 51
  • 52. Prepared exclusively for Clojure 101 Course participants load and refer Clojure libraries. For example, the round function lives in clojure.contrib.math. In order to make round available in the current namespace, call use on round's namespace: (use 'clojure.contrib.math) ; => nil The simple form of use shown above causes the current namespace to refer to all public vars in clojure.contrib.math. This can be confusing, because it does not make explicit which names are being referred to. Remember to pass the :only option to use, listing only the vars you need: (use '[clojure.contrib.math :only (round)]) ; => nil Now you can call round without having to qualify its name: (round 1.6) ; => 2 The ns macro, mentioned earlier, changes the default namespace. It is typically used at the top of a source file. It supports the directives :require, :use and :import (for importing Java classes) that are alternatives to using their function forms. Using these is preferred over using their function forms. Here, symbols become keywords, and quoting is no longer required. (ns notes (:use [clojure.contrib.math :only (gcd, sqrt)]) (:import (java.text NumberFormat) (javax.swing JFrame JLabel))) (println (gcd 27 81)) ; => 27 (println (sqrt 7)) ; => 2.6457513110645907 (println (.format (NumberFormat/getInstance) Math/PI)) ; => 3.142 ; the code below requires you to have knowledge of the Java programming language ; also see the generated image below (doto (JFrame. "Hello") (.add (JLabel. "Hello, World!")) (.pack) (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE) (.setVisible true)) @ 2010 by Satish Talim Page 52
  • 53. Prepared exclusively for Clojure 101 Course participants More on Bindings An example: (def cnt 1) ; cnt is a global binding (defn fn1 [] (println "Global binding value of fn1 = " cnt)) (fn1) ; Global binding value of fn1 = 1 let The let special form creates bindings that are local to that form. Its first argument is a vector containing name/expression pairs. The expressions are evaluated in order (i.e. let does its bindings sequentially) and their results are assigned to the names on their left. These bindings can be used in the expressions that follow them in the vector. They can also be assigned to more than once to change their value. The remaining arguments to let comprise the body which is a set of expressions to be evaluated with the new bindings in scope. Functions that are called in the body cannot see the local bindings created by let. Do check- out the let documentation. http://clojure.org/special_forms#let @ 2010 by Satish Talim Page 53
  • 54. Prepared exclusively for Clojure 101 Course participants An example: (def x 1) (def y 1) (let [x 2 y x] (+ x y)) ; => 4 x ; => 1 y ; => 1 Another example: (def cnt 1) ; cnt is a global binding (defn fn1 [] (println "Global binding value in fn1 = " cnt)) (defn fn2 [] (println "fn2: before let cnt (still global binding) =" cnt) ; fn2: before let cnt (still global binding) = 1 (let [cnt 2] ; creates local binding cnt that shadows global one (println "fn2: in let, cnt (now local binding) =" cnt) ; fn2: in let, cnt (now local binding) = 2 (fn1)) ; Global binding value in fn1 = 1 (println "fn2: after let cnt (back to global binding) =" cnt)) ; fn2: after let cnt (back to global binding) = 1 (fn2) binding The binding special form is similar to let, but it temporarily gives new, thread-local values to existing global bindings. The new values are seen inside that form and also in functions called from inside it. When the binding form exits, the bindings revert to their previous values. An example: Observe below that binding does its bindings in parallel. (def x 1) (def y 1) (binding [x 2 y x] (+ x y)) ; => 3 x ; => 1 y ; => 1 @ 2010 by Satish Talim Page 54
  • 55. Prepared exclusively for Clojure 101 Course participants Another example: (def cnt 1) ; cnt is a global binding (defn fn1 [] (println "Global binding value in fn1 = " cnt)) (defn fn3 [] (println "fn3: before binding cnt (still global binding) =" cnt) ; fn3: before binding cnt (still global binding) = 1 (binding [cnt 3] ; same global binding with new, temporary value (println "fn3: in binding, cnt (global binding value temporarily changed) =" cnt) ; fn3: in binding, cnt (global binding value temporarily changed) = 3 (fn1)) ; Global binding value in fn1 = 3 (println "fn3: after binding cnt (value of global binding reverted back) =" cnt)) ; fn3: after binding cnt (value of global binding reverted back) = 1 (fn3) Symbols that are intended to be bound to new, thread-local values using binding have their own naming convention. These special symbols have names that begin and end with an asterisk. People sometimes refer to the asterisks as "earmuffs". For example, Clojure uses dynamic binding for thread-wide options such as the standard I/O streams *in*, *out* and *err*. The predefined, special symbols *in*, *out* and *err* are set to stdin, stdout and stderr by default. Functions that use these bindings are affected by their values. For example, binding a new value to *out* changes the output destination of the println function. Guideline: As far as possible use let. Use binding when you need a thread-local version of a var. Echo Server We shall build a simple server that accepts network connections and simply echoes back whatever was sent. Port A port is not a physical device, but an abstraction to facilitate communication between a server and a client. @ 2010 by Satish Talim Page 55
  • 56. Prepared exclusively for Clojure 101 Course participants Ports are described by a 16-bit integer value. Hence, a machine can have a maximum of 65536 port numbers (ranging from 0 to 65535). The port numbers are divided into three ranges: the Well Known Ports, the Registered Ports, and the Dynamic and/or Private Ports. The Well Known Ports are those from 0 through 1023 (for example, port no. 80 is for http, port no. 25 is for smtp and so on). The Registered Ports are those from 1024 through 49151. The Dynamic and/or Private Ports are those from 49152 through 65535. Socket A socket is not a physical device but an abstraction. It represents a single connection between two network applications. These two applications normally run on different computers, but sockets can also be used for inter-process communication on a single computer. Applications can create multiple sockets for communicating with each other. Sockets are bidirectional, meaning that either side of the connection is capable of both sending and receiving data. clojure-contrib library The user contributions library, clojure.contrib, is a collection of namespaces each of which implements features that may be useful to a large part of the Clojure community. Some parts of clojure.contrib may migrate into clojure.core if they prove to be so generally useful. See the clojure.contrib API here - http://richhickey.github.com/clojure-contrib/index.html. server-socket API To build this simple server, we shall make use of the server-socket API from the clojure.contrib library. We shall use the following from this API: http://richhickey.github.com/clojure-contrib/server-socket-api.html (ns your-namespace (:require clojure.contrib.server-socket)) (create-server port fun) The above code creates a server socket on port. When accepting a connection, a new thread is created which calls: (fun input-stream output-stream) @ 2010 by Satish Talim Page 56
  • 57. Prepared exclusively for Clojure 101 Course participants duck-streams API We shall also make use of the duck-streams API from the clojure.contrib library. We shall use the following from this API: http://richhickey.github.com/clojure-contrib/duck-streams-api.html (ns your-namespace (:require clojure.contrib.duck-streams)) This library defines "duck-typed" I/O utility functions for Clojure. The 'reader' and 'writer' functions will open and return an instance of java.io.BufferedReader and java.io.PrintWriter, respectively, for a variety of argument types - filenames as strings, URLs, java.io.File's, etc. 'reader' even works on HTTP URLs. spit function Let’s make a little diversion. We shall have a look at the spit function from the clojure.contrib library. This function is not used in the Echo Server. Usage: (spit f content) Opens f with writer, writes content, then closes f. Here's an example: (use '[clojure.contrib.duck-streams :only (spit)]) (spit "rubylearning.out" "Hello RubyLearning participants.") You should now find a file at rubylearning.out with contents Hello RubyLearning participants. Step 1: Define a namespace (ns echo (:use [clojure.contrib server-socket duck-streams])) @ 2010 by Satish Talim Page 57
  • 58. Prepared exclusively for Clojure 101 Course participants Step 2: Define a port (def port 2222) Our server socket would be listening on this port defined by the port variable. Step 3: Define a function Our function handle-client takes two arguments named in and out. In this case it will be streams attached to the client's socket. binding binds names to new values temporarily. in and out are the default streams that the standard IO functions read from (stdin) and write to (stdout). But within the body of this binding block, they will now refer to readers and writers for the client socket. This way we can use functions like read-line and println to communicate with the client. In fact, in our block we read a line and print it out. loop begins the loop and recur returns to the start of the loop. (defn handle-client [in out] (binding [*in* (reader in) *out* (writer out)] (loop [] (println (read-line)) (recur)))) Step 4: Start the server To start the server, type the following in your REPL: (def server (create-server port handle-client)) Finally we call create-server with two arguments - the port number and the function we want to handle the client connections. We keep this in the server var. A lot of the concurrency issues are handled by Clojure inside the create-server function. We don't have to worry about firing-up threads or doing other kinds of listeners. It will handle that under the covers. So that's it for a simple echo server. Our echo server is running at port 2222 on localhost. @ 2010 by Satish Talim Page 58
  • 59. Prepared exclusively for Clojure 101 Course participants Here's the complete code of our Echo Server: (ns echo (:use [clojure.contrib server-socket duck-streams])) (def port 2222) (defn handle-client [in out] (binding [*in* (reader in) *out* (writer out)] (loop [] (println (read-line)) (recur)))) (def server (create-server port handle-client)) Step 5: Test the Echo Server Open a command window and use Telnet to connect to our Echo Server: telnet localhost 2222 Now anything I type in will be echoed back. StructMaps The defstruct macro is used to define a StructMap: (defstruct account-struct :name :balance) The structure field names of type keyword or symbols are automatically usable as functions to access fields of the structure. This is possible as structures are maps and this feature is supported by maps. This is not possible for other types of field names such as strings or numbers. It is quite common to use keywords for field names for structures due to the above reason. The object returned by defstruct is what is called the structure basis. This is not a structure instance but contains information of what the structure instances should look like. @ 2010 by Satish Talim Page 59