4 ms·
Again this is not fundamentally tied to whether functions and variables share a namespace, in clojure they do and yet your example above does not cause a proble
by patrec 6y ago
Again this is not fundamentally tied to whether functions and variables share a namespace, in clojure they do and yet your example above does not cause a problem. Watch:
Let's start out with a function:
user=> (defn enlist [x] (if (list? x) x (list x)))
#'user/enlist
user=> (let [list 1] (enlist list))
(1)
Create a (pointless) equivalent macro:
user=> (defmacro enlist' [x] `(let [y# ~x] (if (list? y#) y# (list y#))))
user=> (let [list 1] (enlist' list))
(1)
No hygiene and yet it works!
How? The secret is that backquote is automatically namespace qualifying:
user=> '(list 1 2 3)
(list 1 2 3)
user=> `(list 1 2 3)
(clojure.core/list 1 2 3)
In practice this + convenient gensym syntax (also demonstrated above) seems to be enough, just like in practice Common Lisp's approach of separate value and function cells for symbols + prohibition of rebinding function cells of symbols in the standard COMMON-LISP namespace is. Scheme has no cl style namespaces and no prohibition on redefining standard bindings and thus came up with a much more complex macro approach, at the gain of stronger hygiene guarantees (but see article above!) and the cost of an ugly design of considerable complexity that has a completely different sublanguage (non-orthogonally) baked in.
As far as purely hygiene is concerned that's IMO not a good trade-off at all; I could rattle off a long list of major usability gripes with both cl and clojure but problems caused by lack of macro hygiene wouldn't be on it.
Racket, which is basically several iterations beyond R*RS macros, OTOH is interesting because it's more principled approach gives you something qualitatively different to what you can do with clojure (no read-syntax control; bad error messages) and common lisp (readtables suck and break tooling; bad error messages).
- kazinator 6y agoI'd have to say that a ham-fisted read-time solution which throws important backquote identities under the bus is worse than just coding carefully under the threat of unhygienic macros, and worse than the complexity of hygienic macros.
- patrec 6y agoWhat concrete problem do you see with it? [edit: BTW you can quite easily implement common-lisp style backquote in clojure as a macro, because just like scheme clojure does not share common lisp's defect of baking unquoting into the readtable dispatch of backquote; i.e. unquotes outside of backquotes are syntactically valid; '~x -> (unquote x)]