4 ms·
Can you explain why "((= a 2) (setq a 3))" has parentheses in that statement? Ideally without just saying "for the same reason as <some other example>"? Becaus
by lgas 12y ago
Can you explain why "((= a 2) (setq a 3))" has parentheses in that statement? Ideally without just saying "for the same reason as <some other example>"? Because I don't see any value in having them in that example.
(cond (= a 1) (setq a 2)
(= a 2) (setq a 3))
Seems like it could serve exactly the same purpose?
- mcguire 12y agoI really did mean to have a question mark at the end of my comment. I'm not actually sure of the answer. The initial thought would be for structure: cond takes any number of arguments, each made up of a conditional -> expression pair. Your suggestion, which is exactly my initial belief before it burned me back in the day, would make cond take an alternating list of conditions and expressions; clearly that's not nearly as beautiful. The structural argument is wrong, though, and your suggestion doesn't work at all. For what must have seemed practical reasons at the time, the expression side is an implicit PROGN, so you can do "((= a 2) (setq a 3) (setq b (potato)))".[1] Common Lisp has some wacky syntax. Large chunks of which are historically (hystorically?) path-dependent. Anyone who tells you otherwise risks calling up the viscous LOOP troll. In Clojure, the defmacro thingy looks like it takes muliple expressions after the params in the body there, so it needs ()'s around the individual cases. [1] http://www.lispworks.com/documentation/lw60/CLHS/Body/m_cond.htm http://www.lispworks.com/documentation/lw60/CLHS/Body/m_cond...
- bdonlan 12y agoIn 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).