Hacker News new | past | comments | ask | show | jobs | submit login
Clojure's mini languages (fogus.me)
62 points by silkodyssey on March 23, 2010 | hide | past | favorite | 25 comments



I don't really understand how the Clojure syntax-quote somehow prevents name-capturing any more than that of Common Lisp does(except for the foo# gensym shortcut). The Common Lisp backquote automatically qualifies symbols in the current package. In fact, the Common Lisp reader does that for all symbols used without a qualified namespace. It would be terribly painful to write in any language with a mandatory package system which could not infer the package to which a symbol belongs in this way.

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 :(


I've often wondered this. Last week rich hickey mentioned this at clojure NYC, and they only things he mentioned were the fully qualifying namespaces (which resolves to the original package it was defined in) and the auto gensyms. I assume this is enough in most cases and the auto gensyms take care of the rest. I don't think I'd trust namespace rewriting by itself though.


Right, and one without the other doesn't do the trick. You need both auto-gensyms and namespace resolution to ensure hygiene in Clojure macros (cleanly at least). On the other hand as lg mentioned you can intentionally capture using the pattern described. So you get the best of both worlds with the stipulation that the case of intentional capture is a bit more cumbersome.


Nice. I bought a MEAP of Fogus' Clojure book: I assume that all of his mini-articles will be in the book.


I'm trying not to recycle the blog posts, but in some ways it's impossible. This specific post will not make it in, but all of the topics will be covered where applicable. Thanks for buying the MEAP; I hope you like it so far.


His site has a console mode...and its pretty awesome. I've never really heard great things about "The Joy of X" books but if the books are as excellent as his blog posts I may have to chip in.


I feel a bit sorry to ask but : how does one access a site in "console mode" ?


In the head of the site look for this "Run This Blog In Mobile Or Console Mode..." click Console mode.


Hey, pretty cool. I had no idea about the (-> ... ... ) macro. I loved how F# (and Haskell) made that same thing really easy, but it turns out Clojure did too. Heh.

Now if only I could get it working on Windows.


I realize this has nothing to do with the content of your post, but your blog has the best title of all time.


It starts with

> 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?


> 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.


> Most of those things listed are neither, rather they are pragmatic and intended to improve readability.

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.


Your point highlights what i think is one of the biggest features of clojure: it has been assembled according to a philosophy / design criteria such that each feature exists as part of the whole. The features that have been omitted from clojure are as important as the features that have made it in.

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.


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.

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


> The problem with C++ is that those "improvements" are grafted onto the language. You can't do a damn thing about it.

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 do know C++. I've used it do OpenGL and basic augmented reality stuff, I've used it in conjunction with Objective-C. And it was one of my first languages.

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.


"It's intended to improve readability when used properly."

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.


The terms syntactic-soup and misfeature are yours. I would not describe the features listed that way, nor did my original post. Likewise, with "achievement" -- I provided a survey of, in my view, useful features independent of context and best-practices. There is no particular reason for me to be proud, but I would think that Rich Hickey would deserve to be so since he's the one who has actually "achieved" something great by creating Clojure. You may not see it that way (clearly not), but it's probably best to keep the level of discussion on merits of this feature or that rather than false pretenses.


The language has many strengths. This is one; it is not the whole.


"I hope you don't judge me by this strength of mine, I'm actually an OK guy" - how does that parse :-P


I don't see how those two statements are conflicting. He begins by saying that it is one of the (implied) multiple strengths of Clojure. He then admits that perhaps it is not for everyone, that Clojure has other features that may be more appealing to others.


500 error :(


I was playing on the server at the time... should be fine now.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: