Ok, this might be hard to keep up, but nothing ventured …
Rich Hickey is going to be coming to Northampton on March 20th to talk about clojure. In preparation for that, I am going to blog every day in March about clojure — then, hopefully we can post the results of his talk.
If you don’t have clojure yet — go get it. Start here to learn basic clojure syntax (there is also a download link). Clojure is trivial to get running and you definitely want to play with it a little to understand the rest of this. The quick description of clojure is that it’s a dialect of Lisp that runs on the JVM. It has support for immutable and persistent data-structures and a concurrent programming model.
Today I’m going to start with some of the work I did to learn clojure through translating SICP lectures. In the first lecture, the first interesting program starts at 56:20 in this video:
Starting there presumes you know some basic Lisp syntax. This is the program he eventually writes to calculate the square root (in Scheme):
(define (improve guess x)
(average guess (/ x guess)))
(define (good-enough? guess x)
(< (abs (- (square guess) x)) .001))
(define (try guess x)
(if (good-enough? guess x)
guess
(try (improve guess x) x)))
(define (sqrt x) (try 1 x))
I have left out implementations for square and average here. This code and the algorithm is explained in the video. Here it is in clojure (I defined average and square — you could just use Java, but I am trying to keep it all in clojure for now)
(defn sum ([] 0)
([x] x)
([x & more] (+ x (apply sum more) )))
(defn average
([] 0)
([x] x)
([x & more]
(/ (+ x (apply sum more)) (+ 1 (count more)))))
(defn abs [x] (if (< x 0) (- x) x)) (defn square [x] (* x x))
(defn improve [guess x]
(average guess (/ x guess)))
(defn good-enough? [guess x]
(< (abs (- (square guess) x)) 0.001))
(defn try-sqrt [guess x]
(if (good-enough? guess x)
guess
(try-sqrt (improve guess x) x)))
(defn sqrt [x] (try-sqrt 1 x))
(prn (sqrt 9))
If you take this and put it in a file named sqrt.clj, you can run it like this (after downloading clojure):
java -cp clojure.jar clojure.lang.Script sqrt.clj
And it will print out:
65537/21845
Explanation of the differences between the two examples:
- clojure uses defn to define functions and puts arguments in []
- sum and average implementations show how clojure can overload on arity (number of arguments)
- try is reserved for exception handling, so I renamed the try function to try-sqrt
- the answer is in clojure’s rational number format, since all of the computation was adding and averaging integers and rationals, the result is a rational number and clojure preserves that.
Tomorrow, I’ll improve this so to make it more generic. A lot of what I used in this can is explained in the clojure Functional Programming support page.