This article is part of a series describing a port of the samples from Practical Common Lisp (PCL) to Clojure. You will probably want to read the intro first.
This article covers Chapter 6, Variables.
Functions can close over their lexical environment, in both Common Lisp and Clojure. The PCL example for this is the canonical simple counter. You might think you could do something like this in Clojure:
This poor counter can only count once:
inc
returns the increment of counter
, but it doesn't change counter
. You might look for a setf
equivalent in Clojure, but you won't find one. Clojure data structures are immutable.
Of course, we don't really need mutable data here. What we need is a mutable reference to data, that can change to point to a different value later. Clojure provides this via Software Transactional Memory (STM).
Using STM, I can create a ref with ref
, and alter a ref with alter
. The alter
must be inside a transaction, a.k.a. a dosync
block.
With all that in mind, here's counter
:
This counter
actually works. (It is also thread safe).
Nothing stops multiple functions from closing on the same variables. Here is a function that returns an incrementer, decrementer, and accessor, all sharing the same counter:
Note that deref
does not require a dosync
wrapper.
Common Lisp provides defvar
and defparameter
to create variables. Between them, these forms provide ways to specify an initial value, documentation string, and init-once semantics.
Clojure's support for these ideas lives partially in clojure.contrib.def
. Having used def, I can use defvar
to specify an initial value and a documentation string:
You can then access the value or the docstring:
For one-time initialization, you can use init-once
:
In addition to init-once
, the form above also demonstrates an alternate docstring syntax. The #^{...}
invokes the metadata reader macro. Here the metadata is a docstring, but the mechanism is general. Clojure also uses metadata for visibility (e.g. private
), and for adding type information.
In Common Lisp, you can rebind global (dynamic) variables with let
. In Clojure, there is a separate binding
macro for this purpose. The following example demonstrates the difference between bind
and let
in Clojure:
This prints:
let
creates new lexical bindings for a
and b
, which shadow the global variables. Inside the let
's call to print-a-and-b
these local bindings are not in scope.binding
creates new dynamic bindings for a
and b
. These are thread local, but visible for the entire dynamic scope of the binding
, including the call to print-a-and-b
.In Clojure, it is idiomatic to use names like *foo*
for variables intended for dynamic rebinding.
Basic creation and binding of variables in Clojure should make sense to a Common Lisp programmer.
The sample code is available at http://github.com/stuarthalloway/practical-cl-clojure.