demi
demi

Reputation: 5504

Clojure: Apply or to a list

This question similar to say, In clojure, how to apply 'and' to a list?, but solution doesn't apply to my question. every? function returns just a boolean value.

or is a macro, so this code is invalid:

(apply or [nil 10 20])  ; I want to get 10 here, as if 'or was a function.

Using not-every? I will get just boolean value, but I want to preserve semantics of or - the "true" element should be a value of the expression. What is idiomatic way to do this?

My idea so far:

(first (drop-while not [nil 10 20]))  ; = 10

Upvotes: 3

Views: 545

Answers (2)

Leon Grapenthin
Leon Grapenthin

Reputation: 9266

A simple macro:

(defmacro apply-or
  [coll]
  `(or ~@coll))

Or even more abstract

(defmacro apply-macro
  [macro coll]
  `(~macro ~@coll))

EDIT: Since you complained about that not working in runtime here comes a version of apply-macro that works in runtime. Compare it with answers posted here: In clojure, how to apply a macro to a list?

(defmacro apply-macro-in-runtime
  [m c]
  `(eval (concat '(~m) ~c)))

Notice that this version utilizes that parameters are passed unevaluated (m is not evaluated, if this was a function, it would throw because a macro doesn't have a value) it uses concat to build a list containing of a list with the quoted macro-name and whatever the evaluation of form c (for coll) returns so that c as (range 5) would be fully evaluated to the list that range returns. Finally it uses eval to evaluate the expression.

Clarification: That obviously uses eval which causes overhead. But notice that eval was also used in the answer linked above. Also this does not work with large sequences due to the recursive definition of or. It is just good to know that it is possible.

Also for runtime sequences it makes obviously more sense to use some and every?.

Upvotes: 3

cobbal
cobbal

Reputation: 70723

you might be able to use some for this:

(some identity [nil 10 20]) ; = 10

Note that this differs from or if it fails

(some identity [false]) ; = nil
(or false) ; = false

Upvotes: 7

Related Questions