Reputation: 18625
Are there non-macro versions of and
and or
in Clojure?
Update: In this case I don't care about the short circuiting.
Upvotes: 7
Views: 3701
Reputation: 70211
This actually came up as a topic on clojure-dev recently. Rich Hickey ultimately concluded they should be added to core for 1.3 as every-pred and any-pred (logged as CLJ-729). I think further discussions there have led them to now be called every-pred (the and variant) and some-fn (the or variant). The final version was just recently committed to master.
Upvotes: 3
Reputation: 5463
Most cases where you want this there is a more idiomatic way to do it, but just an exercise, it is possible to defer evaluation by thunking. Thunk your expressions and give them to logical operators that evaluate the the thunk when needed, using the standard and/or:
(defn &&* [& fns]
(cond (= 1 (count fns)) ((first fns))
:otherwise
(and ((first fns)) (apply &&* (next fns)))))
(defn ||* [& fns]
(cond (= 1 (count fns)) ((first fns))
:otherwise
(or ((first fns)) (apply ||* (next fns)))))
Example use:
(map
(partial apply &&*)
(map (partial map constantly) ;; thunk all of these values
[["yes" "no"]
[false true]
[true "something"]
[true "something" "false"]]))
("no" false "something" "false")
Another Example:
(defmacro thunks
"convert expressions into thunks to prevent advance evaluation"
[& exprs]
(let [fns# (map (fn [e] `(fn [] ~e)) exprs)]
(cons 'vector fns#)))
(apply ||* (thunks (+ 1 2) false (* 1 5)))
3
(apply &&* (thunks (+ 1 2) false (* 1 5)))
false
(apply &&* (thunks (+ 1 2) (* 1 5)))
5
Upvotes: 1
Reputation: 24044
or
The function some
"Returns the first logical true value of (pred x) for any x in coll, else nil."
So you could use (some identity coll)
for or
. Note that its behaviour will differ from or
when the last value is false
: it will return nil
where or
would return false
.
and
If you don't need to know the value of the last form in the coll
vector, you can use (every? identity coll)
for and
. This will differ from the behaviour of the and
macro in that it returns true
if all of its arguments are truthy. See larsmans' answer if you need the result of the last form.
Upvotes: 8
Reputation: 363627
Let land
stand for "logical and", then they're trivial to define:
(defn land
([] true)
([x & xs] (and x (apply land xs))))
Or, slightly closer to the standard and
behavior:
(defn land
([] true)
([x] x)
([x & xs] (and x (apply land xs))))
And similarly for or
.
Upvotes: 5
Reputation: 51501
If you mean functions: no, and they cannot be. The reason is that function forms always evaluate all their arguments before applying the function to their value. You do not want that here.
Upvotes: 1