Jacques Mattheij

Technology, Coding and Business

baby steps in clojure

I’ve set my mind on learning a functional programming language this year, and after long reading and puzzling I’ve decided that it is going to be clojure. Other contenders were Erlang, Haskell, common lisp and scheme.

Clojure seems to have a lot of direct application to the kind of stuff I’m likely to do and it looks like it is gathering a fair amount of steam.

Hga on Hacker news posted this http://news.ycombinator.com/item?id=1033503 very helpful comment so I started reading from the top adding stuff I found along the way. As a warm-up I’ve been reading ‘LISP’ by Winston and Horn.

2010/01/10/05:15 http://en.wikibooks.org/wiki/Learning_Clojure

notes: data types, #3, clojure contains an interesting trick, apparently it does equality comparison by looking at a hash for an object, but what if the hash collides ? You can only really use the hash to test for unequal, if the hash matches it should be followed by an actual inspection of the underlying values. Curious how clojure handles that under the hood.

Clojure defaulting to ‘boxed’ (wrapped) java objects rather than primitives might have some negative performance impact.

Never realized the origin of the word ‘arity’, it’s from unary, binary, tertiary etc:

http://en.wikipedia.org/wiki/Arity

notes on the language:

\e \t \tab \newline \space

are characters

nil == null

vars are mutable, have a ‘root’ binding and a ‘thread local’ binding

ns is the clojure namespace

in-ns sets current namespace import imports class objects in to the current namespace refer refers the interned Vars of another namespace into the current namespace.

valid symbol characters:

alphanumeric characters and * + ! / . : - _ ?

no : or digit as first character

collections:

list: (53 “moo” asdf)

vector: [53 “moo” asdf]

hashmap: {35 “moo” “quack” 21}

sequence:

interface to lists, vectors and hashmaps that implements first and rest

; indicates a comment

Symbol evaluation:

hedgehog/rabbit ; a symbol resolving to the root binding of the Var mapped to rabbit in the namespace hedgehog

java.util.Arrays ; a symbol resolving to the Class Arrays in the package java.util

Resolution of a non-qualified symbol is more complicated:

  1. If the symbol is the first item in a list and matches one of the dozen special form names, the list is a special form and evaluated specially (discussed shortly).
  2. If not, the symbol might map to a Class referred in the current namespace.
  3. If not, the symbol might map to a local variable (a local variable is created by special forms, as we’ll see).
  4. If not, the symbol might map to a binding of the Var interned or referred in the current namespace. (This may be the root binding or a thread-local binding, as previously discussed.)
  5. If not, the symbol resolves to nothing, and an exception is thrown.

List evaluation:

A non-empty list handed to the evaluator should start either with a symbol or another list. If a list starts with a symbol:

  1. As stated above, a list beginning with a non-qualified symbol matching a special form name is evaluated specially.
  2. Otherwise, the symbol may resolve to a Var containing a macro (a special kind of function, as we’ll see), in which case the remaining elements of the list are left unevaluated and passed to a call to the macro. The value returned by the macro is then substituted in place of the macro call and then evaluated.
  3. Otherwise, the symbol should resolve to a Var containing a function, in which case the remaining elements of the list are evaluated (left-to-right) and then passed to a call to the function. Evaluation of the list returns the value returned by the function.
  4. Otherwise, an exception is thrown.

Special Forms:

(if moose a b) ; if moose is not false or nil, return a; otherwise, return b (if (frog) (cow)) ; if (frog) returns something other than false or nil, return value of (cow); otherwise, return nil

(quote (foo ack bar)) ; returns the list (foo ack bar)

(var goose) ; return the Var mapped to goose

(def george -3) ; set / change the value of that Var to -3

(fn a b) ; returns a function which returns the sum of its two arguments

(fn [a b & c] …) ; takes 2 or more arguments; all arguments beyond 2 are passed as a list to c (fn [& x] …) ; takes 0 or more arguments; all arguments passed as a list to x

; a local scope in which aaron is bound to the value 3 ; while bill is bound to the value returned by (moose true) (let aaron 3 bill (moose true) (print bill))

host (‘.’):

(. foo bar 7 4) ; call the method bar of the instance/class foo with arguments 7 and 4 (. alice bob) ; return the value of public field bob of the instance/class alice

Interpreting the sample code at the beginning of the page:

; define a function called ‘words’ ; return a list of words from the parameter ‘text’ to the function ; that match regexp [a-z]+ after calling the java function ‘tolowercase’ on the ; string argument text.

(defn words text))

(defn train features))) {} features))

(def nwords (train (words (slurp “big.txt”))))

(defn edits1 word] (distinct (concat (for i (range n) (subs word (inc i)))) (for i (range (dec n)) (nth word (inc i)) (nth word i) (subs word (+ 2 i)))) (for i (range n) c alphabet c (subs word (inc i)))) (for i (range (inc n)) c alphabet c (subs word i)))))))

(defn known words nwords] w)))

(defn known-edits2 word nwords e2 (edits1 e1) :when (nwords e2)] e2)))

(defn correct word nwords (known (edits1 word) nwords) (known-edits2 word nwords) [word])] (apply max-key #(get nwords % 1) candidates)))

2010/01/10/08:45 done reading

2010/01/11/00:45 found this http://github.com/ericlavigne/island-wari

after asking on HN for some pointers.

That little project uses ‘leinginen’ (what a name), http://zef.me/2470/building-clojure-projects-with-leiningen

Installing leiningen is reasonably simple, after the self-install as ‘root’ you do the rest as a normal user.

Unfortunately I can’t seem to get the ‘regular’ jar to work, but the standalone one works fine.

Never used ‘git’ before!

apt-get install git-core

git clone git://github.com/ericlavigne/island-wari.git

lein compile lein uberjar

java -jar island-wari-standalone.jar

And it works, on localhost:8084 the game appears

HN Submission/Discussion
If you read this far you should probably follow me on twitter: