tags:

views:

169

answers:

5

From what I understand about apply, it unpacks a list and turns the elements into arguments for a function.

I see that (apply + [1 2 3]) works as expected, i.e: it's equivalent to (+ 1 2 3).

Why then is (apply or [true false]) invalid? Isn't it equivalent to (or true false) ?

+9  A: 

Because or is a macro, not a normal function. You can get the same effect with (some identity [true false]).

Chuck
Ah. Thanks! Can you think of any alternatives?
Trilok
`(reduce #(or %1 %2) false [true false ...])`
Brian Carper
I thought `some` was `(comp first filter)` myself until Chouser kindly made me see the more complex reality. Try `(some :a [{:a false} {:a nil} {:a true}])`, then replace `some` with `(comp first filter)`.
Michał Marczyk
@Michal: Very good correction. Thanks for setting me straight. I've removed that bit from the post, though I will note for anyone reading that `some` *is* equivalent to `(comp first filter)` in this particular case — they both do the same thing and give the same result.
Chuck
+3  A: 

As an alternative to or you can use (some predicate coll).

clojure.core/some ([pred coll])
Returns the first logical true value of (pred x) for any x in coll, else nil. One common idiom is to use a set as pred, for example this will return :fred if :fred is in the sequence, otherwise nil: (some #{:fred} coll)

Bozhidar Batsov
+2  A: 

You can try some with true? and false? predicates,


user=> (some true? [true false false])
true
user=> (not (some true? [true false false]))
false
user=> (some false? [true false false])
true
user=> (not (some false? [true false false]))
false

Hamza Yerlikaya
beware of false?! (false? nil) returns false despite nil being considered false. (boolean nil) returns false though.
cgrand
A: 

or is a macro, which you can't use as value.

Create an anonymous function, expanding or at runtime via eval:

(apply #(eval (list* 'or %&)) [true false])
Jürgen Hötzel
Since you can get the same result more naturally without macros (by doing `(reduce #(or %1 %2) false ...)`), this is one of the cases where using `eval` is a bad idea. Case in point: Your form doesn't do what `or` does. Try using it on the vector `['(or) false]`, for instance.
Matthias Benkard
A: 

One of the important things to note though is the evaluation model. or short-circuits, therefore: (or true :some random expression that never gets evaluated:) never evaluates the last. or is traditionally used as much as a control structure as a 'logical or'.

In the traditional model of (f x y z), x, y, and z are evaluated, and f is applied to them.

In the use of (apply f vec) the contents of the vector are not evaluated, they are taken as is. This is most clearly visible with a vector of symbols, they do not evaluate in this context to their bindings. However, this is obfuscated by the fact that Clojure's model for vector creation is some-what different then other lisps, [a b c d] yields a vector which contains the evaluations of the symbols a, b, c, and d. Contrasting most Lisps, wherein #(a b c d) does not evaluate the symbols, and just is identical to evaluating (vector 'a 'b 'c 'd) (or in fact (apply vector '(a b c d))).

So even if it were possible to apply special syntactic forms, it's result would have an opaque semantics. or first evaluates its first argument, if true, it stops and returns that, else it goes to the second and repeats until at the last. In the case of apply, the arguments are already all evaluated, should it then evaluate some a second time? Most likely resulting into a runtime error along the way?

From an implementation perspective, it would be very performance enhibative if syntax was were also 'objects' and would require a much more complex evaluation model. So they are not resolved at runtime, but rather rewritten to compiler primitives at compile time.

But, for this very reason, when or is used logically rather than as a control structure, I myself find it handy to have functions or/f, and/f, if/f, et cetera available which are true procedures and evaluate all of their arguments and thus can be applied.

Lajla