Install Eclipse, if you haven’t already. To get a “main-stream” IDE for Clojure, install the CounterClockwise plugin for Eclipse. I use it with Eclipse Indigo, but I have no idea whether other versions will work too.
The webpage for the plugin can be found here: http://code.google.com/p/counterclockwise/. Use the Eclipse help menu to install extra software, add the update site: http://ccw.cgrand.net/updatesite/.
Select the Clojure plugin. Next, accept, next, finish, restart Eclipse. Then File->New… select Clojure project. Finish. To create a file, right-click on the project, select New->Other->Clojure namespace. To load/start a REPL (Read-Eval-Print-Loop) for the file, right-click the editor, and select load into REPL. Your functions are now accessible in the REPL.
Some notes on the IDE:
Type the following expression in the REPL.
(print "Hello world!")
(+ 1 2)
(+ 1 2 3 4)
*
(map (fn [x] (+ x 2)) [1 2 3 4])
(def f (fn [x] (+ x 2)))
(defn g [x] (+ x 2))
(map f [1 2 3 4]))
(vec (map f [1 2 3 4])))
(reduce * [1 2 3 4])
(if (> 2 1) 'yes 'no)
Quoting
'()
'4
'(+ 3 4)
'[Hello world!]
(quote (+ 3 x))
(list '+ 3 x)
`(list '+ 3 x)
(let [x 3] `(+ 3 ~x))
(let [x '(4 5 6)] `(+ 3 ~@x))
(let [x '(4 5 6)] (concat (list '+ 3) x))
doseq
and range
.reduce
and repeat
.In Clojure, a macro is defined using defmacro
:
(defmacro m [a1 … an] body)
Here, m
is the name of macro, a1 … an
are the formal parameters and body
is the body of the macro. Macros are functions that return code. How the result is created does not matter, but it is typical to use the quasiquote (backtick, `), unquote (~
) and unquote splicing (~@
). Note that when a macro is invoked (m e1 … en)
, the argument expressions e1 … en
are not evaluated. In other words, the formal parameters a1 … an
of m
are bound to the code trees of e1 … en
. For instance, when calling (m (+ 1 2))
, a1
is bound to '(+ 1 2)
and not to 3
.
Tips for debugging macros:
Use macroexpand
and macroexpand-1
with a quoted macro invocation as argument to inspect what a top-level macro expands to.
To see complete expansion of a macro, first issue
(use 'clojure.walk)
at the REPL prompt, then you can use macroexpand-all
.
Write a macro that implements an assert statement, as found in Java. The macro should be called as follows:
(assert* cond "some message")
The result of assert*
should be nil). If the condition cond
fails (i.e., returns false
or nil
) an exception should be thrown with a message containing the literal expression cond
and the label string.
Use throw
to throw an exception, which can be created as follows (Exception. "some message")
. Use the str
function to concatenate strings. NB: the failing expression should be in the message. Tip: unquotes (~
) can be in quotes ('
)…
Does assert*
have to be a macro? If so why? If not, how would you implement it?
Practical Common Lisp devotes a chapter to writing a simple unit-test framework using macros:
The let
construct to introduce local variables is a built-in special form in Clojure. However, it is well-known that let
can be implemented as a macro: an invocation of let
expands to a function application. Write such a macro. Your version of let (let*
) should expand as follows:
(let* [var exp] body) => ((fn [var] body) exp)
To simplify the exercise, you may assume that let
only binds a single variable. If this is too simple, implement another version that supports multiple bindings.
Write a macro times
that takes an expression e
and a number n
and expands to a do
form that just executes the expression n
times. E.g.:
(times 5 'hello) => (do 'hello 'hello 'hello 'hello 'hello)
Tip: use the splicing unquote ~@
in combination with the core function repeat
. Note that repeat
generates an (lazily) infinite sequence, you have to provide the number of repetitions.
Partial evaluation is a program optimization technique that can be applied if certain arguments to a function are statically known. A traditional example is the power
function. Often, the exponent argument (n
in (power x n)
) is statically known. Can we specialize the power function for a fixed n
? Partial evaluation in general is not for the faint of heart, but using macros we can do this specifically for power.
The goal is to write a macro that generates the code for a power function that is specialized for some n
. Let’s call it gen-power
. Now, if (gen-power 3)
returns a function f
, then it should hold that (= (f x) (power x 3))
for all x
.
Here’s an example of what the invocation (gen-power 3)
could expand to:
(fn* ([x]
(clojure.core/* x
(clojure.core/* x
(clojure.core/* x 1)))))
NB: fn*
is an internal form Clojure to represent functions. Note that the *
function has been qualified with the namespace it is defined in. In the macro you can just use the normal fn
and *
to generate code.
Split the solution in two parts:
(gen-body 'x n)
, where x
represents the name of the parameter of the created function, and where n
is the exponent.gen-body
function recursively creates an expression to multiply x
n
times.Argue why the specialized power functions produced by gen-power
would/should be faster than the general power
function.
Check out this page to refresh your derivative chops:
In this exercise, the goal is to compute the derivative of restricted, but otherwise ordinary Clojure functions. The restrictions are:
*
, +
, the formal parameter of the function, and constant numbers.*
and +
only have two arguments (although Clojure supports an arbitrary number).Basically, such functions describe simple polynomials. An example is the following:
(fn [x] (+ (* 3 (* x x)) (+ (* 2 x) 1))))
The derivative of this function is:
(fn [x] (+ (* 6 x)) 2))
The exercise is to write a macro that returns and expression that computes this function. NB: this does not mean that it is syntactically the same as the derivative shown above; it should however give the same answers for the same inputs.
The macro is invoked as follows:
(deriv (fn [x] (+ (* 3 (* x x)) (+ (* 2 x) 1)))))
Split your solution in two parts:
fn
argument to obtain the name of the parameter and the body expression, passes it to 2), and upon return constructs a new fn
with the same parameter.diff
that receives and expression e
and a variable name v
which computes the derivative expression.Some useful functions:
(number? x)
: returns true if x
is a number.(symbol? x)
: returns true if x
is a symbol.(first x)
, (second x)
: return the first resp. second elements of a collection (vector or list) x
.(nth x n)
: return the n
-th element of a collection x
.(cond c1 e1 … cn en :else e)
: cascading conditional; finds the first ci
that evaluates to true and evaluates ei
. If no ci
is found, evaluates e
.