eddology • by edd dumbill

Have a few hours spare and fancy getting to know Clojure and ClojureScript?

Sometimes all you need to get learning a new programming language is the right size problem. Nothing too trivial or too daunting. Fortunately, while reading NN Taleb’s book “The Black Swan”, I got a right-sized idea.

Taleb describes a coin-tossing game you can play to derive a Gaussian distribution for yourself. If the coin lands heads, you win $1. If tails, you lose $1. After a suitable number of tosses, record your net winnings. Repeat this again some number of times. Plot the frequency of each final amount and you’ll find the familiar bell curve. (You can get a similar curve just by recording the number of heads, but it’s not as much fun without the highs and lows of gambling!)

I decided to implement a simulation of this game in Clojure. And beyond that, to package it up in a way that other people can use, and then to use it as an example of how to create a ClojureScript application that runs in the browser.

Screenshot of ClojureScript demo

The coin toss demo running in ClojureScript

Buckle up, the whole thing will take a few hours, but by the end you’ll have an idea of what a Clojure program looks like, and how they’re run and compiled. If you want to skip to the end result right now, check out the coin-tosser source on GitHub.

Install Clojure

I’m not going to reproduce installation instructions here, but you can find them on the Clojure Wiki. You need Clojure and Leiningen installed. Leiningen, often referred to as “lein”, is an excellent build tool and dependency manager that most Clojure programmers use.

This is a conversation

You really can’t learn a new language without trying to converse in it. We don’t figure out what a word means just because we’ve seen a definition, but because we’ve heard or seen it used in several contexts and can deduce a meaning and appropriate usage from that experience.

The same goes for programming. As you read I’m guessing you’ll be doing the same things I was when I was writing: Googling for information, trying code samples out. I’ve tried to write this so it’ll work as a standalone article, but you’ll have much more fun if you use it as a source of starting points.

Tackling the problem

I’m just a beginner: this article is simply the story of how I went about modeling the coin toss game, mixed in with things I’ve learned by reading about Clojure for a few months. I wrote most of the code interactively in the Clojure REPL, that is the interactive immediate execution mode of running Clojure. You can play with one of these online at TryClojure, or fire one up yourself once Clojure is installed.

I began by modeling the fundamental action in the game, the coin toss. To keep it simple, always a virtue, I decided to craft a function that returned true for heads and false for tails. The expression (= 1 (rand-int 2)) does just that. Here’s the function:

(defn coin-toss []
  (= 1 (rand-int 2)))

This expression defines a function, with defn, that has no arguments, hence the empty parameter list []. Run it repeatedly to convince yourself it works.

user=> (coin-toss)
false
user=> (coin-toss)
false
user=> (coin-toss)
true

You can experiment with unfair coins by altering the definition of coin-toss to make a heads result more or less probable.

Settling scores

Now we’ve got a coin, how much do we win in each round? The rules of the game say we win a dollar for heads, and lose a dollar for tails.

(defn toss-score [toss]
  (if toss 1 -1))

The result of the coin toss is passed as a parameter, and the value of the function is the winnings. Clojure’s if expression simply takes the first value if the passed expression is truthy, or the second value if it’s falsey.

Truthy? Falsey? As with many programming languages, values other than the Boolean true or false can be used in a boolean context in Clojure. To put it simply false and nil are falsey, and everything else is truthy.

Let’s check we get the expected results.

user=> (toss-score true)
1
user=> (toss-score false)
-1
user=> (toss-score (coin-toss))
-1
user=> (toss-score (coin-toss))
1

Repeat offender

Unregenerate gamblers that we are, we’re going to be tossing that coin more than once. Clojure’s repeatedly is the ideal way.

user=> (repeatedly 5 coin-toss)
(true true false false true)

What we get back is a list of results. It’s also a seq. A variety of data structures in Clojures are seqs, such as vectors, lists and hashmaps. It’s a basic interface for sequence types.

Of course, we don’t care as much about the results as how much money we’re getting from them. So, let’s count our net winnings.

The net winnings are the total of each individual winning. First, we want to calculate those individual winnings by applying our toss-score to the result. Try this:

user=> (map toss-score [true false true])
(1 -1 1)

The map function applies another function to a collection repeatedly, returning a sequence of the results. Now, we need to total them with our friend reduce.

user=> (reduce + [1 -1 1])
1

You’ve probably figured out that reduce applies a two-argument function to a collection in order, taking the result of the previous calculation as one of the arguments along with the next item in sequence. In the example above, it’s performing the calculation (+ (+ 1 -1) 1).

A little digression on syntax: you’re probably also wondering why I’m using square brackets, Clojure’s notation for vectors, instead of parentheses above. The short answer is that parentheses tell Clojure to treat the first item in the list as a function and the rest as arguments. Try (reduce + (1 -1 1)) and you’ll get an error message. If you want to use a list, write it as (list 1 2 3) or in the quoted form '(1 2 3).

Let’s put this all together and formulate our function for scoring a run of coin tosses.

(defn count-winnings [results]
  (reduce + (map toss-score results)))

It’s easy enough to test out and get some sample scores.

user=> (count-winnings (repeatedly 5 coin-toss))
-3

Finally, it’s going to be a chore to write all those repeatedly expressions out, so we’ll define a function that says what we actually mean: find the winnings from an experiment with a specific sample size.

(defn sample-score [n]
  (count-winnings (repeatedly n coin-toss)))

Creating all these small functions might not be strictly necessary, but they provide a clarity to the program. I prefer to be working in terms of what the code means rather than what it does.

Run and run and run

We’ve now got enough machinery to run a coin-toss game. In order to gather results, we’d like to run the game repeatedly. Again, it’s about as simple as writing down what we mean.

(defn sample-scores [n m]
  (repeatedly n #(sample-score m)))

What’s with the #()? It’s Clojure shorthand for creating an anonymous function. We could have written the following instead.

(repeatedly n (fn [] (sample-score m)))

Let’s run 20 games of 100 tosses each.

user=> (sample-scores 20 100)
(8 18 -10 2 -6 14 2 0 10 -6 20 0 -4 6 -12 0 2 -12 -6 10)

The final part of the exercise is to count up how many times we get specific results, and chart them. We’ll use a hash-map to store this frequency table. Let’s say we got $0 six times, $-2 twice and $2 four times, we’d end up with a map like this:

{0 6, -2 2, 2 4}

We’re going to look through the scores and do something with each one. As this isn’t just a straight transformation of the list, it’s a clue that we could use reduce as part of our solution. We’re going to start off with an empty map {}, and end up with one full of frequency counts. The function we’ll pass to reduce should take the map as its first argument, along with a score, and then return an updated map. Let’s imagine what this might look like.

user=> (reduce tally-score {} [8 18 -10 2 -6 14 2 0 10 -6 20 0 -4 6 -12 0 2 -12 -6 10])
{0 3, 2 3, -4 1, -6 3, 6 1, 8 1, -10 1, 10 2, -12 2, 14 1, 18 1, 20 1}

Now we just need to figure out the mechanics of tally-score. There are two scenarios to handle for each score.

  1. If the results map has a key for the score we’re processing, we must increment the corresponding value by 1.
  2. If the result map has no key for the score, we need to add the key with the value set to 1.

These scenarios can be handled with the following code, assuming results contains the results map, and score is the current score we’re processing.

(if-let [prev-count (results score)]
  (assoc results score (inc prev-count))
  (assoc results score 1)))

Here’s a chance to use a few new Clojure features:

  • (results score) looks up the key score in the hash-map results. In Clojure, maps are functions. You pass the key, and you get the value. For example, evaluating ({1 "one", 2 "two"} 1) yields "one".
  • if-let performs the bindings in the square brackets, and if they’re all true evaluates the first expression, else the second.
  • assoc returns an updated map with the key-value pair passed as arguments

I typically define these little fragments of code in the REPL and then put them together into a function when I’ve figured out how it should work.

Tally ho!

Putting together the above tallying process, we can create a function that took a seq of scores and returned a map of frequencies.

(defn tally-scores [scores]
  (let
      [tally-score (fn [results score]
                     (if-let [prev-count (results score)]
                       (assoc results score (inc prev-count))
                       (assoc results score 1)))]
    (reduce tally-score {} scores)))

Because we don’t need tally-score anywhere outside of this function, I’ve declared it with let, which makes it visible only inside the scope of the let expression. This example also gives you a clue to what you may have suspected by now, that (defn foo []…) is shorthand for (def foo fn [] (…)). To make it even more concise, we could use letfn.

Let’s try a sample run.

user=> (tally-scores (sample-scores 100 20))
{0 15, -2 18, 2 17, -4 19, 4 8, -6 9, 6 5, -8 2, 8 3, 10 3, 12 1}

Hooray!

Off the charts

To make the bell curve apparent, we can use time-honored basic ASCII art. For each score, we can use a string of asterisks to represent its length. Let’s try with 10.

user=> (repeat 10 "*")
("*" "*" "*" "*" "*" "*" "*" "*" "*" "*")

Great, but that’s a seq of strings, not a string of 10 asterisks. Fortunately, we can use join. This function lives in the clojure.string namespace. Until now we’ve only be using functions from the core namespace. So, we’ll grab join.

user=> (use '[clojure.string :only (join)])
nil
user=> (join (repeat 10 "*"))
"**********"

We can use this in a function chart-line, which we’ll use to represent a line in our chart. Because we want to plot a continuous axis of the scores, we need to allow that our results tally map might have no value for certain scores, so chart-line needs to accommodate a nil.

(defn chart-line [tally val]
  (str val
       "\t"
       (if-let [c (tally val)]
         (join (repeat c "*")))))

Concatenating strings in Clojure is done by passing them as arguments to str. To finish, we’ll create the whole chart. For every score, we want a line of asterisks representing the frequency. This is a task for map. To create every chart line, we want something like the following.

(map chart-line (range lowest-value highest-value))

After a bit of tinkering to get a good-looking graph, this is what I came up with.

(defn chart-lines [scores]
  (let [tally (tally-scores scores)
        low (apply min (keys tally))
        high (apply max (keys tally))
        r (inc (max (Math/abs low) high))
        chart-line (fn [val]
                     (str val
                          "\t"
                          (if-let [c (tally val)]
                            (join (repeat c "*")))))]
    (map chart-line (range (- r) (inc r)))))

You can see I decided I wanted my graph with 0 in the middle, so did a bit of calculation to get there. The interesting construct that you’ve not seen before in this function is apply, which simply applies a function to a seq of arguments. In other words, these two are equivalent:

(apply min [1 2 3 4]) and (min 1 2 3 4)

You’re probably also concerned about Math/abs. Because Clojure is based on the JVM, we have all of Java at our disposal. Here we’re borrowing the abs function from java.lang.Math. Let’s not worry too much about that now, as this is the only Java we bring in.

Let’s run this, and join up each line with a carriage return to get something pretty.

user=> (println (join "\n" (chart-lines (sample-scores 50 10))))
-7	
-6	**
-5	
-4	*****
-3	
-2	************
-1	
0	**********
1	
2	*************
3	
4	*****
5	
6	***
7	
nil

Ta-da! The bell curve. Or something a bit like it. Mission accomplished. One final function to make this easier to run, and we can try as many sample sizes as we like.

(defn chart-scores [scores]
  (println (join "\n" (chart-lines scores))))

Tinker time

If you followed along and want some easy places to start fiddling, try the following exercises.

  • What if the coin was unfair, and returned tails twice as often as heads?
  • Would you get the same graph if you only counted the number of heads results?
  • Adjust the program to count only heads, and alter the charting range so it looks pretty again.

There are a couple of fundamental Clojure concepts that I’ve not really touched, and if you want to at least bluff your way as Clojure-credible, then you should learn about these.

  • Laziness, the idea of not evaluating expressions until they’re needed, and
  • tail recursion, the way you loop.

Get smart

Now we’ve got a bunch of code that works, let’s figure out how to make this into a program that anybody else can use. There are few things that help make look Clojure code smart enough to go out in public.

The first of these is namespaces. As hinted earlier when we looked at clojure.string/join, Clojure lets you organize functions by placing them in a namespace. This stops them stomping on top of other functions with the same name. Because I’m a Brit with a schoolboy sense of humor, I picked the namespace tosser.

Second, though Clojure doesn’t mandate a certain directory hierarchy in the same way Java does, there’s a convention most people adopt that helps things stay readable.

Check out the source code for the experiment we just developed. You’ll see a Leiningen project.clj file in the root, and then the source tucked away in a directory corresponding to the namespace I decided to use, tosser.

Third, in order to make our coin tossing system usable outside of the Clojure REPL, we need to write a “main” entry point that will take command-line arguments and run the experiment in response.

You can find the source in main.clj, but here’s the essence.

(defn -main
  "Main entry point"
  [repetitions sample-size]
  (chart-scores (sample-scores (Integer/parseInt repetitions)
                               (Integer/parseInt sample-size))))

Notice we’re using java.lang.Integer.parseInt to conver the string argument from the command line. Don’t forget that Clojure is a typed language, even though it’s dynamic and doesn’t require type declarations.

The declaration :main tosser.main in project.clj tells the compiler, via Leiningen, which namespace contains the main function of the program.

Once you’ve built the code with lein compile you can invoke it via lein run.

$ lein compile
Copying 1 file to /Users/edd/work/git/coin-toss/clojure/lib
Compiling tosser.main
Compilation succeeded.
$ lein run 50 10
-7	
-6	***
-5	
-4	*********
-3	
-2	**********
-1	
0	**************
1	
2	*********
3	
4	*****
5	
6	
7	

If you want to understand what’s going on at the Java level here, you can also run the program like this:

$ java -cp ./classes:lib/clojure-1.3.0.jar tosser.main 50 10

If you want to hand your program to somebody else, regardless of whether they’ve installed Clojure, use lein uberjar.

$ lein uberjar
Cleaning up.
Copying 1 file to /Users/edd/work/git/coin-toss/clojure/lib
Created /Users/edd/work/git/coin-toss/clojure/tosser-1.0.0.jar
Including tosser-1.0.0.jar
Including clojure-1.3.0.jar
Created /Users/edd/work/git/coin-toss/clojure/tosser-1.0.0-standalone.jar

The program can now be run like this:

$ java -jar tosser-1.0.0-standalone.jar 200 20

If you’re going to check your code into source control, be sure to ignore the classes and lib directories that Leiningen generates.

And that’s about all there is to it. Welcome to computer programming, circa 1995. In the next section, we’ll move into the web age a little.

Getting webby with it: ClojureScript

ClojureScript is a Clojure-like language that compiles to JavaScript. I say “Clojure-like” because ClojureScript isn’t Clojure. It’s a lot more like Clojure than JavaScript is like Java, but they’re not the same.

However, it’s easy enough to port across our Clojure program to give ourselves a first taste of running ClojureScript. It also makes the coin-tossing experiment feel a lot more interactive!

If you browse through the source of the ClojureScript coin-toss experiment, you’ll find it much the same. However, there are a few things to notice.

Firstly, reinforcing the point that it’s a different language, the source code files have the suffix .cljs.

Second, I’ve marked functions that I want to be available to JavaScript with the ^:export notation.

(defn ^:export chart-lines
  "Given a list of scores, create a simple ASCII frequency graph"
  [scores] ... )

The ClojureScript build process uses JavaScript “minification” for compression. The export metadata tells the compiler to leave the name of that function alone, so it’s callable from outside the ClojureScript program.

Third, you might be quietly fretting about the small bit of Java we call, Math/abs. Obviously we’re not going to be calling Java from this program, so what gives? Instead, this is turned into a JavaScript invocation. Fortuitously, JavaScript also has a Math.abs function that does exactly the same thing. We should really write js/Math.abs to call the JavaScript object, but ClojureScript does “the right thing” for built-in JavaScript objects like Math and RegExp.

How do we drive this thing?

First, we need to compile the program. Thanks to our project.clj definition and the lein-clojurescript plugin, this is as simple as invoking lein compile.

ClojureScript compile to JavaScript. In order to run the program, we need to create an HTML page that will load the script and call it. This page looks something like this:


<html xmlns="http://www.w3.org/1999/xhtml">
  <head><title>Coin Toss Demo</title>
    <script type="text/javascript" 
       src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    <script type="text/javascript" src="out/goog/base.js"></script>
    <script type="text/javascript" src="tosser.js"></script>
    <script type="text/javascript" src="ui.js"></script>
    <script type="text/javascript">
      goog.require('tosser.main');
    </script>
  </head>
  ...

The important bits have been highlighted in bold. I’m also using jQuery as part of the demo, but you can ignore that for now. The three script elements achieve the following: they load in the Google Closure JS library, load in the compiled ClojureScript program, and loads our program’s namespace plus any of its dependencies.

This is where it gets a bit silly. ClojureScript uses the Google Closure JavaScript library as a substrate. Yes, “Closure” is pronounced the same as “Clojure”. Just smile politely and move on.

The namespace tosser.main refers to that defined in main.cljs. Rather than have a “main” entry point as we did for the command-line version, I created a new file with the entry point I want for my web page version. It defines a function chart that we can call from JavaScript to get the ASCII chart.

(ns tosser.main
  (:require [tosser.core :as toss]
            [clojure.string :as string]))
(defn ^:export chart [m n]
  (string/join "\n" (toss/chart-lines (toss/sample-scores m n))))

ClojureScript doesn’t yet support Clojure’s use, so we import things we want from other namespaces as part of our ns declaration.

To run the coin-tossing experiment from JavaScript, it’s as simple as calling tosser.main.chart(). If we put the parameters into a form, as seen in the screenshot, we can use jQuery to call the experiment when the user hits the submit button, and then write the results back into the page.

Here’s what the jQuery code to do that looks like, with the invocation to our ClojureScript highlighted. Note that we needed to convert string input to integers. I could equally well have done that in ClojureScript in the definition of chart.

$(document).ready(function(){
    $("form").submit(function(){
	var tosses = parseInt($("#tosses").val());
	var runs = parseInt($("#runs").val());
	$("#results").text(tosser.main.chart(runs, tosses));
	return(false);
    });
});

For a peek at how the ClojureScript program appears to JavaScript, pop open the JavaScript console from your web browser and evaluate a few things. Try this, for example:

> tosser.main.chart(20,5)
"-4	
-3	**
-2	
-1	*******
0	
1	*********
2	
3	**
4	"

When it comes to putting your web page live, you obviously don’t want a million little JavaScript files. Instead, you can recompile with optimizations to end up with just one file, tosser.js. You then don’t have to load Google Closure or perform the goog.require instruction either, as in tosser.html.

$ lein compile '{:optimizations :simple}'
Compiling clojurescript in src ... compiled 2 files to out/ and 'tosser.js' (took 40979 ms)
$ ls -l tosser.js
-rw-r--r--  1 edd  staff  383078 Dec 21 16:13 tosser.js

However, 380k is hardly a small filesize for a simple program. Fortunately, we can specify :advanced for optimizations too, which also minifies the resulting JavaScript. That makes it pretty useless for debugging, but gets the filesize down to 55k. If you use advanced optimization and you want to use jQuery, you’ll need to remember to use jQuery.noConflict() for things to still work.

So, that’s a bit messy!

There’s not actually any reason that I should have complicated my demonstration by using jQuery, except for that I’ve spent the last three years exclusively using jQuery for my JavaScript and it felt a comfortable place to be.

In fact, ClojureScript has enough in it for you to do all the things that jQuery can do using just ClosureScript and the Google Closure libraries. In that case, you may want to keep the Closure Library API Documentation to hand.

In keeping with the rather fluid nature of JavaScript, there’s also a third way. Instead of keeping your jQuery with your HTML files, you can call jQuery directly from your ClojureScript via the js namespace. For example, the jQuery statement

$("body").append("<div>hello</div>");

could be rendered like this in ClojureScript

(.append (js/jQuery "body") "<div>hello</div>")

More idiomatically, we can use the -> (thread macro) from Clojure to chain functions in the same way jQuery does.

(-> (js/jQuery "body")
    (.append "<div>hello</div>")
    (.css "background-color" "red"))

So, pick your poison. For a new application, I’m inclined to try and stick with Google Closure and ClojureScript throughout, but jQuery has many riches that it would be a shame to ignore.

In conclusion

I hope you’ve enjoyed the high-speed romp through Clojure and ClojureScript. I find Clojure to be an enjoyable and natural way of programming.

There’s plenty more to explore, but if you’ve followed along with this project you’ll have a decent grounding. Feel free to use the comments on this article to send questions, bug reports and improvements.

Finally, I recommend picking up a copy of The Joy of Clojure as well. It’s a good read, quite often challenging, but written by people who really enjoy the language.

All the source code for programs developed in this article is available on GitHub.

  1. copywriter-copywriting reblogged this from eddology
  2. nokia-lumia-800-deals reblogged this from eddology
  3. wine-club-subscription-740 reblogged this from eddology
  4. noean reblogged this from eddology
  5. yacitus reblogged this from eddology
  6. technotalk reblogged this from eddology
  7. eddology posted this
Blog comments powered by Disqus