Clojure函数定义中的运算符优先级是什么?

时间:2013-12-29 04:43:44

标签: function clojure operator-keyword operator-precedence

假设我们定义如下函数,Clojure中的运算符优先级是什么?

(defn leap-year? [input-year] (or (and (= (rem input-year 4) 0) (> (rem input-year 100) 0)) (= (rem input-year 400) 0)))

3 个答案:

答案 0 :(得分:10)

S-expressions明确具有优先级和关联性,因为它们代表树。

与许多LISP方言一样,Clojure以“大量刺激的多余括号”直言不讳地展示了这些:

  

在计算中,s表达式,sexprs或sexps(用于“符号表达式”)是嵌套列表(树形结构)数据的符号,由编程语言Lisp发明并推广,它使用它们作为源代码。以及数据。在通常的带括号的Lisp语法中,s表达式通常被归类地定义为

     
      
  • 一个原子,或
  •   
  • 形式(x.y)的表达式,其中x和y是s-表达式。
  •   

就优先级和关联性而言,“运算符”与任意函数调用(或宏)没有区别。也就是说,Clojure代码有效开始生活Abstract Syntax Tree而形式(+ a b)(fn a b) - +令牌本身并不相同,就像fnadd只是生成的S表达式中的 atom

格式化代码应该更多地显示树结构(并且可以扩展此格式,直到一行只包含一个原子和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表达式,但andormacrosand的实施是:

(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表达树建立。

此外,从实现中可以看出,逻辑条件表单也从左到右进行了延迟评估,就像在许多其他流行语言中一样。

答案 1 :(得分:6)

在Clojure中没有运算符优先级。所有函数从左到右和从里到外进行评估,所有函数都在宏扩展阶段之后完成。

答案 2 :(得分:1)

Clojure中有 no 运算符优先级,因为没有运算符是这样的:+-=>等等只是功能。

您可以使用编辑器(我使用Clooj)缩进代码以显示其结构:

(defn leap-year? [input-year]
  (or
    (and
      (= (rem input-year 4) 0)
      (> (rem input-year 100) 0))
    (= (rem input-year 400) 0)))

您可以通过提取本地函数(我称之为divides-by)来使逻辑更清晰,以告诉您input-year是否正确地除以数字。

(defn leap-year [input-year]
  (let [divides-by (fn [d] (= (rem input-year d) 0))]
    (or (and (divides-by 4) (not (divides-by 100))) (divides-by 400))))

注意

andor,在编译器看到之前会被翻译成其他内容。例如,(or x y)变为(if x x y)。这种并发症在这里没有效果。