Clojure's mini languages
blog.fogus.me
blog.fogus.me
What makes Clojure's backquote so much more resilient against variable capture than Common Lisp's?
CL-USER> (progn (defmacro foo () `(let ((bar 1)) bar)) (foo))
1
user=> (do (defmacro foo [] `(let [bar 1] bar)) (foo))
java.lang.Exception: Can't let qualified name: clojure.core/bar
EDIT: sorry if that was cryptic, see Lisp will let you say (let ((cl-user::bar 1)) cl-user::bar)
but clojure won't let you do (let [clojure.core/bar 1] clojure.core/bar)
You can't use fully-qualified names that way. So namespace resolution in expansions prevents capture. If you really want capture, you can do ~'bar to protect it from resolution. Well I hope that's still true, lotrepls doesn't seem to like it :(Now if only I could get it working on Windows.
> one of the strengths of Clojure is that it is comprised of many little mini-languages
and ends with (in the comments)
> I hope you do not judge the whole of Clojure by this blog post
So which is it? Is this syntactic soup an achievement to be proud of or a misfeature to ignore and avoid?
Most of those things listed are neither, rather they are pragmatic and intended to improve readability.
* List comprehensions need no justification.
* Literal regex support also needs no justification.
* Syntax quote needs no justification.
* Literal numerics need no justification.
Stuff you might not use: * pre/post conditions
* gen-class
I hardly consider ns a mini-language any more than I consider any language's import syntax a mini-language but that's me.So we're left with #() and ->, ->>.
#() is often abused. It's really meant for things like this:
(map #(* % 3) (range 100))
; vs.
(map (fn [x] (* x 3)) (range 100))
It's intended to improve readability when used properly.This the purpose of -> and ->> as well. People often complain that Lisp code needs to be read inside out.
(+ (* (/ x 2) 3) 5))
; vs.
(-> x (/ 2) (* 3) (+ 5))
Again a readability win, not loss.The road to damnation is paved with good intentions. In C++, (which I use a lot for many practical reasons), separately every single feature solves or improves something, but together the improvements could have been made more consistently at a lesser cost in language elegance.
It has been pointed out that much of what is in clojure is not new, its the careful and pragmatic orchestration of good ideas taken from across the field of computer science that makes it interesting. The major point of conflict is whether you agree with the philosophy.
The problem with C++ is that those "improvements" are grafted onto the language. You can't do a damn thing about it.
In Clojure half these "mini-languages" are just macros. You don't have to use any of it. If you see a better way to do things build your own macros from the primitive forms.
Good luck fixing C++ :D
You don't have to use the features you don't like. Its main design principle is "you don't pay for what you don't use".
The problem with C++ is that too many people who don't know it, talk about it :-P
I haven't worked with it in a very long time (4+ years) and I never did very large projects (more than 10,000 LOC) with it. For that I am glad.
Which was the point of my poorly worded comment on the post. I presented a survey of Clojure's "mini-languages" features without usage context. I wasn't trying to give a run-down of best-practices, so if the post came off as my trying to do so then I failed.
Thanks for providing some perspective.