【问题标题】:what is the operator precedence in Clojure function definition?Clojure 函数定义中的运算符优先级是什么?
【发布时间】:2014-01-16 07:36:16
【问题描述】:

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

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

【问题讨论】:

    标签: function clojure operator-keyword operator-precedence


    【解决方案1】:

    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 表达式中的一个 原子

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

    此外,从实现中可以看出,逻辑条件形式也像许多其他流行语言一样从左到右惰性求值

    【讨论】:

      【解决方案2】:

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

      您可以使用编辑器(我使用 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)。这种并发症在这里没有影响。

      【讨论】:

        【解决方案3】:

        在 Clojure 中没有运算符优先级。所有函数从左到右和由内向外求值,都在宏扩展阶段之后完成。

        【讨论】:

          猜你喜欢
          • 2017-10-13
          • 2011-10-25
          • 2018-06-21
          • 1970-01-01
          • 1970-01-01
          • 2016-11-18
          • 1970-01-01
          相关资源
          最近更新 更多