Update: The Clojure Koans GitHub repo moved. Instructions below have been updated.
I attended my first Chicago Clojure meetup and 8th Light’s Colin Jones introduced us to Clojure Koans, a Ruby Koans inspired set of tests to teach you Clojure, a functional programming language. After finishing the koans that night, I have a better understanding of how Clojure syntax works. You might have heard Clojure uses a lot of parentheses - it’s probably not an overstatement.
Here’s how to get started and reach your way to enlightenment.
Clojure Koans is on GitHub. First let’s do a git clone:
[~/local/git] git clone https://github.com/functional-koans/clojure-koans.git Cloning into clojure-koans... remote: Counting objects: 487, done. remote: Compressing objects: 100% (210/210), done. remote: Total 487 (delta 264), reused 487 (delta 264) Receiving objects: 100% (487/487), 60.71 KiB, done. Resolving deltas: 100% (264/264), done. [~/local/git] cd clojure-koans [master][~/local/git/clojure-koans]
Here’s a quick look at the directory. Note: Clojure Koans is no longer a branch of Functional Koans.
[master][~/local/git/clojure-koans] ls -lah total 64 drwxr-xr-x 10 skim staff 340B Jan 2 12:49 ./ drwxr-xr-x 55 skim staff 1.8K Jan 2 12:49 ../ drwxr-xr-x 13 skim staff 442B Jan 2 12:49 .git/ -rw-r--r-- 1 skim staff 32B Jan 2 12:49 .gitignore -rw-r--r-- 1 skim staff 3.7K Jan 2 12:49 README.md -rw-r--r-- 1 skim staff 13K Jan 2 12:49 epl-v10.html -rw-r--r-- 1 skim staff 504B Jan 2 12:49 ideaboard.txt -rw-r--r-- 1 skim staff 165B Jan 2 12:49 project.clj drwxr-xr-x 10 skim staff 340B Jan 2 12:49 script/ drwxr-xr-x 5 skim staff 170B Jan 2 12:49 src/
Cool, now let’s install Leiningen (pronounced ‘LINE-ing-en’) to grab the latest Clojure jar. We’ll need this jar along with JRE 1.5 or higher. Most Macs should have JRE installed by default.
To install Leiningen, simply download this script, place it in your $PATH (e.g., ~/bin) and chmod it.
I placed my copy in ~/bin and ran chmod on it.
[~/bin] ls -lah total 48 -rw-r--r--@ 1 skim staff 6.0K Jun 19 2010 .DS_Store -rwxr-xr-x 1 skim staff 221B Jun 19 2010 ack* -rw-r--r--@ 1 skim staff 5.6K Jan 2 13:05 lein -rwxr-xr-x 1 skim staff 2.2K Jun 19 2010 mvim* [~/bin] chmod 755 lein [~/bin] ls -lah total 48 -rw-r--r--@ 1 skim staff 6.0K Jun 19 2010 .DS_Store -rwxr-xr-x 1 skim staff 221B Jun 19 2010 ack* -rwxr-xr-x@ 1 skim staff 5.6K Jan 2 13:05 lein* -rwxr-xr-x 1 skim staff 2.2K Jun 19 2010 mvim*
Now let’s run the lein executable.
[~/bin] ./lein Downloading Leiningen now... % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 6794k 100 6794k 0 0 1780k 0 0:00:03 0:00:03 --:--:-- 2905k Leiningen is a build tool for Clojure. Several tasks are available: classpath Show the classpath of the current project. clean Remove compiled artifacts and jars from project. compile Compile Clojure source into .class files. deps Download all dependencies and place them in the :library-path. help Display a list of tasks or help for a given task. install Install the current project or download the project specified. interactive Enter interactive shell for calling tasks without relaunching JVM. jar Package up all the project's files into a jar file. javac Compile Java source files. new Create a new project skeleton. plugin Manage user-level plugins. pom Write a pom.xml file to disk for Maven interop. repl Start a repl session either with the current project or standalone. run Run a -main function with optional command-line arguments. test Run the project's tests. test! Run a project's tests after cleaning and fetching dependencies. uberjar Package up all the project's files and dependencies into a jar file. upgrade Upgrade Leiningen to the latest stable release. version Print version for Leiningen and the current JVM. Run lein help $TASK for details. Also available: readme, tutorial, copying, sample, and news.
Excellent, we have Leiningen installed. Now let’s go back to the clojure-koans directory and run lein deps. This will read the project.clj file to find out which dependencies it needs to install.
[master][~/local/git/clojure-koans] lein deps Downloading: org/clojure/clojure/1.3.0-alpha3/clojure-1.3.0-alpha3.pom from central Downloading: org/clojure/clojure/1.3.0-alpha3/clojure-1.3.0-alpha3.pom from clojure Transferring 1K from clojure Downloading: jline/jline/0.9.94/jline-0.9.94.pom from central Downloading: junit/junit/3.8.1/junit-3.8.1.pom from clojure Downloading: junit/junit/3.8.1/junit-3.8.1.pom from clojure-snapshots Downloading: junit/junit/3.8.1/junit-3.8.1.pom from clojars Downloading: junit/junit/3.8.1/junit-3.8.1.pom from central Downloading: org/clojure/clojure/1.3.0-alpha3/clojure-1.3.0-alpha3.jar from central Downloading: org/clojure/clojure/1.3.0-alpha3/clojure-1.3.0-alpha3.jar from clojure Transferring 3528K from clojure Downloading: jline/jline/0.9.94/jline-0.9.94.jar from central Downloading: junit/junit/3.8.1/junit-3.8.1.jar from clojure Downloading: junit/junit/3.8.1/junit-3.8.1.jar from clojure-snapshots Downloading: junit/junit/3.8.1/junit-3.8.1.jar from clojars Downloading: junit/junit/3.8.1/junit-3.8.1.jar from central Copying 3 files to /Users/skim/local/git/clojure-koans/lib
Ok, now I’m not sure how this works exactly on Windows, but Mac and Linux, you should be able to run koans this way:
[master][~/local/git/clojure-koans] script/run FAIL in [email protected] (equalities.clj:1) We shall contemplate truth by testing reality, via equality. expected: (= __ true) actual: (not (= nil true))
Great! If you read through the error message, you’ll see there’s something wrong in the equalities.clj file. All files live in the src/koans directory. Open it up, fix the tests and re-run the previous command. For the sake of showing you an example, I fixed the first test:
[master][~/local/git/clojure-koans] cat src/koans/equalities.clj (meditations "We shall contemplate truth by testing reality, via equality." (= true true) "To understand reality, we must compare our expectations against reality." (= __ (+ 1 1)) "You can test equality of many things" (= (+ 3 4) __ (+ 2 __))) [master][~/local/git/clojure-koans] script/run FAIL in [email protected] (equalities.clj:1) To understand reality, we must compare our expectations against reality. expected: (= __ (+ 1 1)) actual: (not (= nil 2))
Now fix the next test and you’ll be on your way to enlightenment.
If you ever get to functions.clj, tell me how you implemented the last one! Here’s mine:
"Higher-order functions take function arguments" (= 25 ((fn [n f] (f n)) 5 (fn [n] (* n n)))))