Learn A New Language

March 4, 2014

I chose to implement my modest prime-number library in Clojure. Clojure is similar to Scheme, which actually made things harder for me, not easier, because my fingers kept typing things all by themselves. Of course, that’s the point of the exercise, to break those habits and make you think about what you are doing. Here’s my library:

I was surprised not to find gcd in the base libraries of Clojure. This looks familiar, of course. I like the addition of doc strings; some Scheme systems provide them as a non-standard addition to the language, and they provide useful documentation.

Clojure permits internal function definitions, just like Scheme, so again there is nothing new here. I constantly had trouble with the parentheses that Clojure omits — my fingers type them automatically — and I made use of Clojure’s optional comma operator to separate the clauses of the let. I’m not sure I like the new syntax; it seems to me that it would be easy to mess up a complicated cond expression by mis-matching the clauses. I discovered during testing that Clojure seems to have no way to write powers of ten as big integer literals, analogous to Scheme’s #e1e40.

It didn’t take me long to realize that what Clojure calls vectors aren’t really vectors; instead, they are trees with 32-way branching, so lookup is O(log32 n) instead of O(1). That’s not a big difference, but it makes a huge difference. It took me longer to realize that what Clojure calls lists aren’t really lists, either; they’re just backwards vectors, there are no pairs as in Scheme, so no improper lists, and somehow Clojure keeps track of the length of a list because length is an O(1) operation. Clojure arrays, as used above, are what I expect them to be. The recur syntax performs a recursive call, and must be in tail position; I suppose that’s a reaction to the lack of tail call elimination in the JVM, but it will take some getting used to.

I normally implement this test using a witness list of the first twenty-five primes, but I couldn’t figure out a way to store that list in the function so that it didn’t have to be re-computed each time the function was called. So I switched to twenty-five random witnesses, and had trouble with that before I realized that rand-int is limited to the native integer size and doesn’t permit big integers. And one of the tests that I always use is 289−1, which is prime, but I couldn’t figure out a way to compute 289−1 because the powering operation uses floating point numbers instead of big integers.

I was pleased to see that Clojure provides sort as a built-in; some Scheme systems don’t, including the Scheme at codepad.org that I use for all my sample code. I was less pleased, though, that Clojure seems to provide no way to have two nested loops, analogous to Scheme’s named-let, instead using the recur syntax to provide only a single level of looping. I solved that problem by splitting the rho loop into a separate function, but that seems awkward to me, and harms readability.

Erlang does not have a facility to create a cirular list, so to create the wheel I create a new process (actually a very lightweight thread) to simulate a generator that can yield a new value each time it is called.