LoLClojure – Chapter 3

Chapter three of Land of Lisp is all about Lisp syntax. This post will be sort of scattered as far as content goes, since the chapter covered a lot. Many things are the same in Clojure, but there are some serious differences. The first is how to define a function.

Defining Functions

In Lisp, you use defun, but in Clojure, it’s defn. Here’s a square function in Lisp.

(defun square (n) 
  (* n n))

And here’s the same function in Clojure. Notice that the function arguments are enclosed in square brackets (it’s a vector), instead of parens.

(defn square
  "Returns the square of the passed-in number"
  [n]
  (* n n))

That string is known as the docstring. It stays with the function, and is available in the REPL by running the doc function, like this (doc square). Lisp also supports docstrings in functions, but it comes after the argument list, instead of before. While docstrings are optional, I highly encourage you to include them. They can span multiple lines, and since they stay with your function, they are useful from the REPL.

Equality

In Lisp, there are may functions for determining equality, and you have to choose the right one for any given circumstance. Among these are eq, equal, equalp, and a few others. In Clojure, there’s just =. If you’re coming from Java, you know = by itself is assignment, not an equality check. For that, you have to use ==, but even that only computes reference equality, and is not always what you want. In Clojure, = does everything you want, in every circumstance. It is your friend.

Exponentiation

Starting on page 34, there are a few examples using the expt function, which raises its first argument to the power of its second. This is a built-in function in CL, but Clojure doesn’t have one. You could use Math.pow from Java, but this only works with doubles, and once the numbers get really large, it switches to scientific notation.

(Math/pow 2 2)       ; 4.0
(Math/pow 2 3)       ; 8.0
(Math/pow 2.0 3)     ; 8.0
(Math/pow 2 10)      ; 1024.0
(Math/pow 53N 53)    ; 2.4356848165022712E91

(In case you haven’t seen it, appending an N to a number literal causes the number to be of type clojure.lang.BigInt. Appending an M makes it a java.math.BigDecimal.)

You can write your own exponentiation function that gives better results than using the one from Java. Here are two different ways to write it. Both versions are tail-recursive, which means they won’t exhaust the stack, but the first uses a nested function, while the second is recursive on a loop. Here’s the nested function version

(defn expt
  "Raise x to the nth power"
  [x n]
  (letfn [(rexpt [n acc]
                 (if (zero? n)
                   acc
                   (recur (dec n) (* acc x))))]
    (rexpt n 1)))

Notice the letfn that contains a local function called rexpt. This function does all the work, and is called as the last line of the main function. It takes a parameter to be used as an accumulator, and this is returned once the exponent is decremented to zero. This nested function is also a closure, because the value of x is referenced directly. We don’t need to change it like we do n, so we just use its name.

Now, here is the version that uses loop. While CL has a loop macro, Clojure’s loop is completely different. All it does is provide a recursion point. This means that when you use the recur function later, execution will jump back to where the loop call is, instead of back to the beginning of the function. The locals declared in the loop’s vector are rebound with the values specified by the recur call. I think this version is easier to understand than the first one.

(defn expt
  "Raise x to the nth power"
  [x n]
  (loop [n n
         acc 1]
    (if (zero? n)
      acc
      (recur (dec n) (* acc x)))))

Notice that the code inside the loop is identical to that in the rexpt local function from the previous example. It’s just not wrapped inside another function. Also of note is in the let we assign n to n. This is a common technique, and will result in a local called n being assigned the value of the passed-in n. The local n can then be decremented with each recursion, without affecting the outer n.

Both of these function provide identical results.

(expt 2 2)       ; 4
(expt 2 3)       ; 8
(expt 2.0 3)     ; 8.0
(expt 2 10)      ; 1024
(expt 53N 53)    ; 24356848165022712132477606520104725518533453128685640844505130879576720609150223301256150373

Notice that passing in an integer results in an integer. Passing in a double results in a double. And passing in a BigInt results in a very large number (Hint: scroll horizontally… it goes on for a while).

Printing Things

CL uses (princ), (prin1), (print), etc., to output things to the console. In Clojure, you use (print) and (println).

(print "He yelled \"Stop that thief!\" from the busy street.") ; no newline
(println "He yelled \"Stop that thief!\" from the busy street.") ; newline

(print) outputs the string, but does not append a newline. (println) appends a newline, as you would expect, given its name.

To Be Continued…

This has gotten very long, so I will stop now, and continue in another post. Stay tuned for Chapter Three, Part Two.

Advertisements

LoLClojure – Locals

Just like in Lisp, Clojure uses let to define locals. The only real difference is that Clojure uses a vector of names and their bindings, whereas Lisp uses a nested list.

This Lisp code

(let ((a 5)
	  (b 6))
  (+ a b))

looks like this in Clojure

(let [a 5
      b 6]
  (+ a b))

I think the Clojure way is a little easier to read.

The biggest difference between the two is when it comes to local functions. CL has flet for defining local functions, and labels for defining local functions that need to be able to call each other (or call themselves recursively). Here’s an example of each

;; A single local function
(flet ((f (n)
		  (+ n 10)))
  (f 5))

;; Two local functions that don't need to call each other
(flet ((f (n)
		  (+ n 10))
	   (g (n)
		  (- n 3)))
  (g (f 5)))

Here’s the equivalent code in Clojure. Note how the square brackets make things stand out a little bit more.

(letfn [(f [n]
           (+ n 10))]
  (f 5))

(letfn [(f [n]
           (+ n 10))
        (g [n]
           (- n 3))]
  (g (f 5)))

If the functions need to reference each other, in CL you have to use labels, instead of flet. Here’s how that looks (the only difference is the form used; the arguments remain the same)

(labels ((a (n)
			(+ n 5))
		 (b (n)
			(+ (a n) 6)))
  (b 10))

In Clojure, you don’t need to use anything other than letfn, because it already supports the recursive nature that labels provides

(letfn [(a [n]
           (+ n 5))
        (b [n]
           (+ (a n) 6))]
  (b 10))

Finally, if you have local functions and other local bindings you need to establish, you can use a let, but no recursion is supported. This is sort of like CL’s flet but you can also use it for binding locals that are not functions

(let [a (fn [n]
          (+ n 5))
      b (fn [n]
          (+ (a n) 6))
      c 10]
  (b c))

I think the way Clojure uses square brackets in certain places that CL uses parentheses makes the code easier to read, overall.

LoLClojure – Land of Lisp In Clojure

I read Conrad Barski’s excellent book Land of Lisp a couple of years ago, and worked through all the examples using CLisp, but I thought it might be fun to go through it again, but use Clojure instead. Other people have done it already, but what’s one more, eh?

As I work through the book, I will be putting all the code on Github at https://github.com/joeygibson/lolclojure

So, the first example is for a program to guess a number you are thinking of. In Lisp, defparameter allows you to rebind values, but Clojure’s def is immutable. Using a ref gets around this, though it is a bit clunky (since refs are intended for multi-threaded access.) The code is not great, and you wouldn’t write a Clojure program like this (or a Lisp program, really); it’s just to get the discussion moving. Better code is coming.

Anyway, here’s the number-guessing program in non-idiomatic Clojure. To run it, load it into a REPL, then execute (guess-my-number). If you are so enraptured with the game that you want to play it again, execute (start-over) and then (guess-my-number).

(ns lolclojure.guess)

;; Using refs for these is overkill, but the original
;; used mutable global variables.
(def small (ref 1))
(def big (ref 100))

(defn guess-my-number
  "This is, effectively, a binary search between the two extremes."
  []
  (Math/round (Math/floor (double (/ (+ @small @big) 2)))))

(defn smaller
  "The guess was too high, so lower it."
  []
  (dosync
   (ref-set big (dec (guess-my-number)))))

(defn bigger
  "The guess was too low, so raise it."
  []
  (dosync
   (ref-set small (inc (guess-my-number)))))

(defn start-over
  "Reset everything and prepare to start over."
  []
  (dosync
   (ref-set small 1)
   (ref-set big 100)))