Sixth week, sixth language, this time Clojure, the latest attempt to make Lisp popular.
Clojure has the usual features of Lisp: code as data, macros, lists among many other containers (no, Lisp is not just lists), and so on. It also brings other features, such as pattern matching, and treating some containers as functions for specific purposes (both features that Arc, the language that Paul Graham invented, seems also to have). Pattern matching is certainly a welcome feature; I have to see more Clojure code to figure out whether I like the data as function one (I’m sure it allows very neat idioms).
Clojure is also supports a kind of lazy evaluation, but simpler than Haskell’s.
Finally, Clojure runs on both the JVM and the CLR, which allows it to go wherever either platform goes (which means pretty much everywhere), and to reuse these platforms’ extensive libraries.
The first day covers little, compared to other languages. Various containers are introduced, along with some useful functions operating on them; pattern matching is described (it is similar to Erlang’s and other functional languages); finally we learn how to define functions, and use them in higher-order functions like apply
.
Exercises
Comparatively to previous languages’ first day, today is very short and simple.
Define function big
Nothing special here, the function count
works on all collections, including strings.
1 2 3 4 5 |
|
Testing:
1 2 3 4 |
|
Define function collection-type
Using only functions and concepts seen so far, a first implementation using map. First I use the repl to get the class of these containers:
1 2 3 4 5 6 7 8 |
|
So the empty list has a different class from a non-empty list.
Now I can map these classes to the proper symbol:
1
|
|
With this, getting the right answer is as simple as:
1 2 3 4 5 6 7 8 |
|
So the function can be written as:
1 2 3 4 5 |
|
Testing it on literal values:
1 2 3 4 5 6 7 8 9 10 |
|
Interesting, perhaps, but there must be a better way. Using type predicates (list?
, map?
and vector?
), and the already seen if
):
1 2 3 4 5 6 7 |
|
Testing output is not repeated, as it is identical to the one above.
These nested if
’s are ugly. Fortunately, Lisp has a kind of generalized switch
, called cond
. So the definition above is equivalent to
1 2 3 4 5 6 7 |
|
Now this is clean and elegant.
Once again, the test returns the expected results so they are not reproduced.
One thing to note: the cons
function does not return a list, but a sequence (this is unlike cons
in all the other Lisps):
1 2 3 4 5 6 7 8 |
|
Fortunately, assoc
is better behaved:
1 2 |
|
I like the idea of a collection’s type not changing when I add element, so the behaviour of cons
is something I will have to watch for (or find the better way that must exist).
And this is all for Day 1.