3
Clojure: Where’s the Elegance?
I’ve looked at the relatively new functional programming language Clojure a bit and I have to say, I’m not impressed. Functional programming is an interesting pastime, and I’m sure it has it’s uses, but when it comes to language design, it’s as if the creators are deliberately going out of their way to make things difficult.
This site has a few tips for beginners, but I was especially struck by the section about namespaces, in which the author says, “There’s ns and in-ns and use and require and import…”
What first clued me in to some bad design ideas, however, was Clojure’s sequence functions (see the bottom of the page). The fact that there are 7 separate functions for getting a specific element from a sequence (first, ffirst, nfirst, second, nth, when-first, last) is strongly at odds with my preference for Python’s there-should-be-only-one-way-to-do-it philosophy. Also, why the inconsistency of having first and second functions but no third, fourth, fifth, and so on? (I think we know why.)
I know Clojure is young, but there’s a difference between a language that’s not mature and a language that’s immature. Design features like this don’t make me want to say, “Boy this is great; I can’t wait ’til Clojure is more developed.” It makes me want to say, “Oh grow up.”
This concludes another Truly Pointless Rant.


On all those functions, that’s the lisp way…
“It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures.” -Alan Perlis
Matter of fact, that’s the same for namespaces/packages.
Good news for a n00b is they can just ignore all that for the most part. You just need to learn the base functions. Then you add more over time.
e.g. you can learn to use (first seq) and (rest seq) and combine those to your hearts content. Then when you stumble upon (ffirst seq) you realize you no longer have to write (first (first seq)) How often do you need ffirst -well, not nearly as much as first or nth.
Lisp programmers like a large library of composable variations on a base set of functions. That is kind of a highlight of functional programming. But in OOP the Smalltalk language takes a similar approach: many variation of base methods, e.g. the collection API.
I am not sure why Python would prefer a “one way for one thing” approach, but that would certainly not be the Lisp way.
well if its a cuestion of tastes i think clojure is one of the most elegant languages (maybe haskell is more beautiful but i think the compiler is more complicated)
One of the keys of python is the identation and that makes it simple and elegant but parentheses dont disturb once you get used to them.
With them clojure can have not operators or setences, the core of the compiler is a few special forms. With them clojure.core builds a set of funtions and you can use only one way but yo can choose which one!!
While I like the ideas behind Clojure (stateless, functional programming), I find the execution wanting. It seems to me that the creators wanted a functional programming language for the JVM more than they wanted a better functional programming language, yet the only thing anyone seems to be talking about is that it’s a better functional programming language.
I could do without the JVM, but a better functional programming language would be something to talk about.
If you wanted to do Python-like slicing in Clojure, though granted not as concisely, you could make your own slice function – I am thinking maybe as an inline function via definline instead of as a regular function or macro.
Usage variations could be like the following:
(slice coll [index])
;; and/or simply: (slice coll index)
(slice coll [start end])
(slice coll [start end stride])
And, to get the equivalent of Python slices
where the numeric values are not supplied,
like coll[::-1] and such, you could use any non-numeric such as :_ as a placeholder, like:
(slice coll [:_ :_ -1]).
After thinking about this, I searched and found the following thread that talks about similar stuff – not exactly the same, but has some implementation ideas:
http://www.mail-archive.com/clojure@googlegroups.com/msg17443.html
Python’s my favorite language, but I’ve been learning about Clojure because of the way it handles concurrency. It has its own elegance and consistency in other ways.
Consider this, just to focus on some of what is mentioned in this post: In Python you can slice lists and tuples and strings and even the “generator-like” xrange, but not generators. In Python, if you have a list of lists like:
x = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]
You can do:
x[0][0]
to get ‘a’, whereas in Clojure you might do:
(ffirst x).
Similarly:
x[0][1:]
would give you ['b', 'c'], whereas in Clojure,
you might do:
(nfirst x)
And:
x[2]
Would give you
['g', 'h', 'i']
similar to (nth x 2) in Clojure.
But if you had, say, a generator that returned generators instead… consider the following toy example that returns the same values as above:
x2 = ((chr(x+i) for i in xrange(3)) for x in (97, 100, 103))
You couldn’t handle it the same way in Python since trying to slice x2 (or the generators it produces) would give you:
TypeError: ‘generator’ object is unsubscriptable
But, you can (arguably more consistently than Python in this respect), use those same Clojure functions on Clojure’s lazy equivalent:
(def x2 (for [x [97 100 103]]
(for [i (range 3)] (char (+ x i)))))
(for creates “list comprehensions” in Clojure, but unlike in Python, list comprehensions are lazy in Clojure.)
I am not saying here that Python should have slicing of generators. It works in its own way with generators getting consumed as you call next(). But Clojure has its own goodness going on with its immutable and persistent data structures. Python is awesome, but Clojure is worth delving more into.
Well, you can use nth(0) for first, nth(1) for second and nth(-1) for last, but which ones are more *readable*? There’re many ways to say in our own human languages for one thing, but we can still understand each other.
As other commenters have mentioned, Pythonic “one way” is not the normal style in a Lisp. But here are a few Clojure things that are cool because many languages provide *zero* ways to do them.
* dosync
* alter
* macros
* auto-gensyms
* defmulti
* destructuring
* persistent data structures
* the *-in functions
* maps as functions
* *warn-on-reflection*
* metadata that is just data
Cheers!
Was this rant meant as satire? The sequence functions were your clue to Clojure’s bad design? Nothing about the cons of immutability, higher order functions, lazy evaluation or any of those other bad design choices that Clojure has? What gives?
Part of the issue here I think is that wrt to computer languages we are accustomed to looking at them from the perspective of “what does language x provide?” With languages like clojure (i.e. homoiconic, macros) the language really only provides you with the primitives and relies on *you* to provide yourself with the rest (or get it from the community).
Me: “What? there’s no tenth function?” Clojure: “Write it yourself. (defn tenth [seq] (nth seq 10))”
Write it yourself is pretty much clojure’s answer for any question. You got a problem with the language? Change it. You don’t want to change it? Fine, don’t use clojure.
Well Eric, thanks for another pointless rant
Original post: “This refrigerator smells funny.”
Comments: “Don’t worry about it, mine smells even worse.” “Yeah, just put a peg on your nose and ignore it.” “Other fridges don’t have nearly as much stuff in them.” “Why don’t you mention the ugly fridge magnets on the front door?” “Clean it yourself!”