clojure koans is awesome

Jul 29, 2010

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.

Installation

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
[email protected] 1 skim  staff   6.0K Jun 19  2010 .DS_Store
-rwxr-xr-x  1 skim  staff   221B Jun 19  2010 ack*
[email protected] 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
[email protected] 1 skim  staff   6.0K Jun 19  2010 .DS_Store
-rwxr-xr-x  1 skim  staff   221B Jun 19  2010 ack*
[email protected] 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

Running Clojure Koans

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.

functions.clj

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)))))

Have fun!