Reputation: 616
My question is pretty similar to this one: How to evaluate a sequence of impure functions in Clojure? but instead of impure functions, how can I evaluate sequence of pure functions and get the results as another sequence?
Let's assume we have a vector of functions like:
[#(str "a" "b") #(str "c" "d") #(str "e" "f")]
And we need an output like this:
("ab" "cd" "ef")
I've tried something similar to this:
(map eval [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
but it just returns a vector of function references.
Upvotes: 2
Views: 352
Reputation: 426
Maybe it's worth to have a look at pcalls
and/or pvalues
(pcalls #(str "a" "b") #(str "c" "d") #(str "e" "f"))
;=> ("ab" "cd" "ef")
Please note that pcalls
is using future
inside!
Upvotes: 0
Reputation: 13473
Note
As Nathan Davis wrote, eval
evaluates a clojure form:
(eval '(+ 1 1)) ;=> 2
What does it do to a function? Nothing!. eval
treats functions as literals:
((eval +) 1 1) ;=> 2
For your case:
(def stuff [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
... we have
(= stuff (map eval stuff)) ;=> true
Though
(= [#(str "a" "b") #(str "c" "d") #(str "e" "f")]
(map eval [#(str "a" "b") #(str "c" "d") #(str "e" "f")]))
;=> false
... since the corresponding functions are different objects, though identical in operation.
That's why eval
is useless to you. So follow Magos's advice.
Upvotes: 1
Reputation: 5766
eval
evaluates a Clojure form (i.e., a list containing "code"). You have functions, not forms.
You map
with apply
, but apply
takes both a function and a seq
of arguments. Since you have no arguments, you can use the empty vector:
(map apply
[#(str "a" "b") #(str "c" "d") #(str "e" "f")]
(repeat []))
But it would be shorter and probably clearer if you use for
:
(for [f [#(str "a" "b") #(str "c" "d") #(str "e" "f")]]
(f))
Upvotes: 1
Reputation: 3659
There are multiple ways to do what you are asking. It depends on whether you want a lazy sequence or not (you probably want lazy given there are no side-effects, but you might want no-lazy if there's an intensive computation that you want to cache), or if you want a vector as output (the same as your input). I'll try to follow what you tried to do.
Your map with eval is doing the following with each fn:
user=> (eval #(str 1))
#<user$eval1332$fn__1333 user$eval1332$fn__1333@38747597>
But you want something like the following:
user=> (eval (#(str 1)))
"1"
You want eval to have the fn applied, that is: the fn should be the first element of a list. Let's put it in a list:
user=> (map (comp eval list) [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
("ab" "cd" "ef")
Cool. But instead of eval, you probably want to use apply:
user=> (apply #(str 1))
; ArityException Wrong number of args (1)
Ups! It failed. apply
doesn't have a 0-arity overload, but we can pass an empty list:
user=> (apply #(str 1) ())
"1"
Much better. Let's do it with map:
user=> (map #(apply % ()) [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
("ab" "cd" "ef")
Or better yet, given your functions receive no arguments, you'd better do as suggested by @Magos:
user=> (map #(%) [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
("ab" "cd" "ef")
Upvotes: 9