Reputation: 345
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
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
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
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