3 ms·
In clojure cond does not have those extra parenthesis - that's a LISPism. cond in clojure works like your example, except that clojure does not have setq. The
by bdonlan 12y ago
In clojure cond does not have those extra parenthesis - that's a LISPism. cond in clojure works like your example, except that clojure does not have setq.
The reason you have those parenthesis on defmacro is that defmacro shares syntax with defn and fn for function declaration; in turn, these allow for multiple side-effecting statements in a function. For example:
(defn my-function [args]
(prn "Hello, world!") ; do something with side effects...
args) ; then return a value
This works fine in the single-dispatch case, but when you're declaring a function that takes multiple arities (with a different implementation dispatched for each), there's no way to tell where each arity ends and the next begins - after all, something like [args] is just data and could easily be a valid expression. The parenthesis are then needed to disambiguate where one arity ends and the next begins:
(defn greet
([] (println "Hello, there!")
(swap! greeting-count inc)
:greeted)
([name] (println "Hello, " name)
(swap! greeting-count inc)
:greeted))
This is a space where clojure seems a bit inconsistent - let, fn, loop, and try all allow multiple expressions, while cond and if don't (but you can get it back using the (do) special form). This however does have some logic to it - let and loop get it for free as they don't need extra brackets to disambiguate, and for fn it's very helpful to be able to just chuck additional statements (debug prints, for example) at the top or bottom without having to wrap in (do). Plus it's free in the more-common single arity case, and keeping it around for multiple-arity keeps things internally consistent. On the other hand, if and cond would require disambiguating syntax to take additional statements regardless, and so that syntax might as well be (do).