4 ms·
Lisp has a different design philosophy. Lisp prefers minial syntax for s-expressions and then Lisp syntax is defined on top of that. Learning what is evaluated
by lispm 12y ago
Lisp has a different design philosophy. Lisp prefers minial syntax for s-expressions and then Lisp syntax is defined on top of that. Learning what is evaluated or not is a part of that.
Using array syntax for arglists is just arbitrary. Clojure is inconsistent anyway.
(defmacro and
([] true)
([x] x)
([x & rest]
`(let [and# ~x]
(if and# (and ~@rest) and#))))
Can you explain why this has parentheses: ([x] x) ? Is that meant to be evaluated?
> Likewise Clojure's `let` syntax does not require wetware parsing to recognize what gets evaluated and what doesn't.
let [x 1
y 3]
(+ x y)
This is all inconsistent. A vector [x 1 y 3] is evaluated. But in LET 1 and 3 are evaluated. x and y not.
> What I am appreciating about Clojure as a language is that it prunes some historic artifacts from the Lisp family tree.
Clojure adds more artifacts than it removes.
> Lisp was developed as a direct improvement over assembly.
Lisp was developed for symbolic computation with recursive functions in the domain of list processing. It has nothing to do with assembler.
> It's a rethinking of what a Lisp needs (when backwards compatibility is ignored).
It's a rethinking what a Java programmer might want as the next step. As Lisp not so much.
> It's an interesting design.
That's true.
- mcguire 12y agoI've only briefly played with Clojure and it's been a very long time since I used Common Lisp a lot, but... "Can you explain why this has parentheses: ([x] x) ?" For the same reason "((= a 2) (setq a 3))" has parentheses in: (cond ((= a 1) (setq a 2)) ((= a 2) (setq a 3))
- lgas 12y agoCan 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).
- lispm 12y agoSo we have a language called Clojure which groups by (... ([x] x) ([x x] x) ...); where there are complex evaluation rules... and [x1 x2 x3], where all x are evaluated and [v1 e1 v2 e2 ...], where only e is evaluated, in LET and [v1 ... vn], where no v is evaluated, in argument lists etc., etc. I somehow fail to see the dramatic improvement over just using parentheses. Instead of learning building basic rules of forming and naming expressions with parentheses, I now learn a few inconsistent rules of forming and expressions with a set of delimiters - which is no problem, but it is not the huge progress you claim.
- mcguire 12y agoYou may be misunderstanding me. I don't claim any progress at all. Only trade-offs and fuzzy areas and lesser or greater poor decisions.