Reputation:
I have this Clojure code:
(defn apply-all-to-arg [& s]
(let [arg (first s)
exprs (rest s)]
(for [condition exprs] (condition arg))))
(defn true-to-all? [& s]
(every? true? (apply-all-to-arg s)))
This is test code:
(apply-all-to-arg 2 integer? odd? even?)
=> (true false true)
(every? true? (apply-all-to-arg 2 integer? odd? even?)
=> false
(true-to-all? 2 integer? odd? even?)
=> true
My question is: Why does the function true-to-all? return true (it must have returned false instead)
Upvotes: 3
Views: 210
Reputation: 6956
The default Clojure function that creates a function that applies several functions to one argument in parallel is juxt:
=> ((juxt integer? odd? even?) 2)
[true false true]
=> (every? true? ((juxt integer? odd? even?) 2))
false
=> (defn true-to-all? [a & fns]
(every? true? ((apply juxt fns) a)))
=> (true-to-all? 2 integer? odd? even?)
false
If the functions you combine with juxt all take multiple arguments it works as well
=> ((juxt + - / *) 6 3)
[9 3 2 18]
Upvotes: 2
Reputation: 33637
You can also defined your function like below to make it more clear.
(defn apply-all-to-arg [v & fns]
(map #(% v) fns))
As this makes the function definition clear that it takes a value and optional functions to apply to that value.
Upvotes: 0
Reputation: 370092
true-to-all?
calls apply-all-to-arg
with the single argument s
. So you're not calling (every? true? (apply-all-to-arg 2 integer? odd? even?)
, but rather:
(every? true? (apply-all-to-arg (list 2 integer? odd? even?))
So in apply-all-to-arg
the value of arg
will be that list and the value of exprs
will be the empty list. Since every?
will be true for the empty list no matter what the condition is, you'll get back true.
To fix this you can either change apply-all-to-arg
, so that it accepts a list instead of a variable number of arguments, or you can change true-to-all?
, so that it passes the contents of s
as multiple arguments rather than a single list (by using apply
).
Upvotes: 3
Reputation: 4782
Because when you call true-to-all?
, the parameter s
is a list, so you are effectively calling (apply-all-to-arg '(2 integer? odd? even?))
Try defining true-to-all?
like this:
(defn true-to-all? [& s]
(every? true? (apply apply-all-to-arg s))
Upvotes: 0