pauldoo
pauldoo

Reputation: 18625

Non-macro versions of clojure "and" and "or"

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

Answers (5)

Alex Miller
Alex Miller

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

rplevy
rplevy

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

intuited
intuited

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

Fred Foo
Fred Foo

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

Svante
Svante

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

Related Questions