The let statement in Clojure

Clojure’s method of assigning a symbol to the result of an expression will look a bit alien to those us used to imperative languages like Java. In Java, to assign a value to a variable, we say something like x = 42;, but in Clojure doing something like this is a bit more involved.

Clojure provides the let statement for assignment. The syntax of let is:

(let [vector of name-value pairs] (expression))

The vector of name-value pairs is the list of assignments that let is to make, and the expression can be any Clojure expression. A simple example will show how this works.

(defn let-test
  (let [x number
        y (* x x)]
    (println "x = " x ". y = " y)))

Here we define a function called let-test which takes one argument, number. Then we have a let statement. Its vector contains two name-value pairs. The first pair assigns number to the symbol x, and the second pair assigns (* x x) (that is, x squared) to the symbol y. Finally, we use println to print out the values of x and y. If we test this from the REPL, we get

user=> (let-test 42)
x =  42 . y =  1764

It is important to realize that the assignments that take place within a let have a scope that is restricted to the let statement. For example, if we had placed the println statement outside the let, we would get a compilation error, since x and y are undefined outside the let. In this respect, let is not equivalent to the simple assignment statements in Java, where an assignment’s scope lasts from the line in which it is made to the end of the function (assuming it is not superseded by another assignment statement).

The let statement can be used to make code more readable and understandable, even if it does make code a bit longer. As an example of a more extended use of let, consider the algorithm for calculating the date of Easter, given the year. Various algorithms exist, some of which give the date in the Gregorian calendar (the one commonly used in the West today) and others in the Julian calendar. We’ll have a look at one of the Gregorian algorithms (the ‘anonymous Gregorian algorithm’ given here). The algorithm uses only arithmetic, but is quite complicated, although it would be easy enough to code it in Java from the version given in the Wikipedia article. In Clojure, we’ll use let to make the assignments to each of the variables given in the algorithm, then print out the date of Easter at the end. The result is as follows.

(ns glenn.rowe.Easter
	(:require clojure.contrib.math)
(use 'clojure.contrib.math)
(defn easter
  (let [a (rem year 19)
        b (floor (/ year 100))
        c (rem year 100)
        d (floor (/ b 4))
        e (rem b 4)
        f (floor (/ (+ b 8) 25))
        g (floor (/ (+ (- b f) 1) 3))
        h (rem (+ (- (- (+ (* 19 a) b) d) g) 15) 30)
        i (floor (/ c 4))
        k (rem c 4)
        L (rem (- (- (+ (+ 32 (* 2 e)) (* 2 i)) h) k) 7)
        m (floor (/ (+ (+ a (* 11 h)) (* 22 L)) 451))
        month (floor (/ (+ (- (+ h L) (* 7 m)) 114) 31))
        day (+ (rem (+ (- (+ h L) (* 7 m)) 114) 31) 1)]
    (println day "/" month "/" year)))

This code introduces the Clojure math library, so it’s useful to see how it is referenced. In the ns statement at the start, we’ve added a require clause, stating that the clojure.contrib.math library is needed for this program. The clojure.contrib library is a standard part of Clojure, so it will have been installed when you installed Clojure, and should be available.

On line 4, the use statement tells the program that functions in clojure.contrib.math are to be used in the code, so we can call these functions just by using their bare name. In fact, the only such function we need is the floor function, which returns the largest integer less than or equal to its single argument. (There is a built-in function called quot which will perform integer division and discard the remainder, so we could have said (quot year 100) instead of (floor (/ year 100)) without using the math library, but I wanted to see how to call functions in the math library.)

The rest of the code is a fairly straightforward translation of the algorithm into Clojure arithmetic functions. The rem function on line 7 is Clojure’s modulus function: (rem x y) returns the remainder when integer x is divided by integer y (it’s equivalent to the % operator in Java). The rem function is part of the Clojure core, so the math library isn’t needed for it.

You can see that let allows a whole series of symbols to be assigned in pairs, by stating the symbol and then the expression whose return value is to be assigned to that symbol. Again, remember that the println statement at the end must be inside the let statement. (American readers will probably want to reverse the ‘day’ and ‘month’ bits of the output.)

Post a comment or leave a trackback: Trackback URL.


  • octopusgrabbus  On January 22, 2012 at 10:12 PM

    One of the toughest things I’ve found transitioning to Clojure is you have to create data scoping hierarchy. For example, if you read data in from a spreadsheet, the Clojure let form allows you to create a binding, and then functions process that data within the let’s scope. I remember transitioning from C to C++ a long time ago, and functional programming transition will be even tougher.


  • By Binary search in Clojure « Programming tutorials on January 31, 2012 at 4:10 PM

    […] the use of the quot function, which calculates the integer quotient, discarding any remainder. Recall that variables defined within a let have a scope that is restricted to the […]

  • By The for macro in Clojure « Programming tutorials on February 9, 2012 at 3:11 PM

    […] that can be applied to each binding. The first is :let, which works in much the same way as the regular let statement. It can be used to define symbols for later use within the for. For example, suppose we wanted to […]

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: