S-expressions 明确具有优先级和关联性,因为它们代表一棵树。
像许多 LISP 方言一样,Clojure 用“大量令人讨厌的多余括号”直言不讳地暴露了这些:
在计算中,s 表达式、sexprs 或 sexps(用于“符号表达式”)是嵌套列表(树结构)数据的表示法,由编程语言 Lisp 发明和推广,将它们用作源代码以及数据。在 Lisp 的常用括号语法中,一个 s 表达式经典地归纳定义为
- 一个原子,或
- (x . y) 形式的表达式,其中 x 和 y 是 s 表达式。
就优先级和关联性而言,“运算符”与任意函数调用(或宏)没有什么不同。也就是说,Clojure 代码有效地开始一个Abstract Syntax Tree 的生命,而(+ a b) 的形式与(fn a b) 没有本质上的不同——+ 令牌,如fn 或add,只是生成的 S 表达式中的一个 原子。
格式化代码应该更多地显示树结构(并且这种格式化可以扩展,直到一行只包含一个原子和 0..n 括号):
(defn leap-year? [input-year]
(or
(and (= (rem input-year 4) 0)
(> (rem input-year 100) 0))
(= (rem input-year 400) 0)))
虽然源表单和扩展表单仍然是 S 表达式,但 and 和 or 是 macros。 and的实现是:
(defmacro and
"Evaluates exprs one at a time, from left to right. If a form
returns logical false (nil or false), and returns that value and
doesn't evaluate any of the other expressions, otherwise it returns
the value of the last expr. (and) returns true."
{:added "1.0"}
([] true)
([x] x)
([x & next]
`(let [and# ~x]
(if and# (and ~@next) and#))))
这允许(and ..)(通过宏的递归扩展),但不允许在产生式中允许“或”术语,因为表单已经由外层 S 表达式树。
此外,从实现中可以看出,逻辑条件形式也像许多其他流行语言一样从左到右惰性求值。