Gopinathan K M
Gopinathan K M

Reputation: 345

what is the operator precedence in Clojure function definition?

Suppose we define function as below , what is the operator precedence in Clojure?

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

Upvotes: 2

Views: 507

Answers (3)

user2864740
user2864740

Reputation: 61875

S-expressions explicitly have precedence and associativity, as they represent a tree.

Clojure, like many LISP dialects, exposes these quite bluntly with "Lots of Irritating Superfluous Parentheses":

In computing, s-expressions, sexprs or sexps (for "symbolic expression") are a notation for nested list (tree-structured) data, invented for and popularized by the programming language Lisp, which uses them for source code as well as data. In the usual parenthesized syntax of Lisp, an s-expression is classically defined inductively as

  • an atom, or
  • an expression of the form (x . y) where x and y are s-expressions.

As far as precedence and associativity, "operators" are no different than an arbitrary function call (or macro). That is, Clojure code effectively starts life an an Abstract Syntax Tree and the form (+ a b) is not inherently different than (fn a b) - the + token, like fn or add, is just an atom in the resulting S-expression.

Formatting the code should show the tree structure a bit more (and this formatting can be expanded until a line contains only a single atom and 0..n parenthesis):

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

While the source and expanded forms are still S-expressions, and and or are macros. The implementation of and is:

(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#))))

This allows (and ..) (via the recursive expansion of the macro), but does not allow "or" terms in the production as the form is already established by the outer S-expression tree.

Also, as can be seen by the implementation, logical condition forms are also lazily evaluated from left-to-right as in many other popular languages.

Upvotes: 10

Thumbnail
Thumbnail

Reputation: 13473

There is no operator precedence in Clojure, because there are no operators as such: +, -, =, > and so on are just functions.

You can use an editor (I used Clooj) to indent your code to show its structure:

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

You can make the logic clearer by extracting a local function (I've called it divides-by) to tell you whether input-year divides by a number exactly.

(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))))

Note

and and or are macros, which are translated into something else before the compiler sees them. For example, (or x y) becomes (if x x y). This complication has no effect here.

Upvotes: 1

Alex Baranosky
Alex Baranosky

Reputation: 50064

In Clojure there is no operator precedence. All functions evaluate left to right and inside out, all done after the macro expansion phase.

Upvotes: 6

Related Questions