Reputation: 23
I've been trying to figure out how to execute expressions that are stored as elements in a sequence. For example, here are two expressions in a sequence:
user=> (def z '((println 'x) 'y))
#'user/z
user=> z
((println (quote x)) (quote y))
Trying to use do or doall on them doesn’t seem to do anything
user=> (do z)
((println (quote x)) (quote y))
user=> (doall z)
((println (quote x)) (quote y))
The output I am trying to get is if I were to execute them not as a sequence but as a list of arguments
user=> (do (println (quote x)) (quote y))
x
y
I tried mapping eval but that gives me an extra nil and returns a list
user=> (map eval z)
(x
nil y)
Any help would be greatly appreciated!
Upvotes: 1
Views: 131
Reputation: 5237
(def z '((println 'x) 'y))
Your z
definition has a quote saying DON'T EVALUATE ME. So z
is defined as an unevaluated expression. You want to evaluate unevaluated code so naturally you'll want to use eval
; however (eval z)
won't work because (println x)
will print x
but return the value nil
. (nil y)
will not work and isn't what you want.
What you do want is do
; do
only returns the value of the last expression so used here nil
does not get in the way and you execute all your expressions. You want your end result to be:
(do (println 'x)
'y))
Let's transform z
to look like that.
(cons 'do z)
=> (do (println (quote x)) (quote y))
Looking familiar? eval
it!
(eval (cons 'do z))
=> x
y
Upvotes: 1
Reputation: 12883
You're looking to eval code here.
user=> (def z '(do (println "hey!" 'x) 'y))
#'user/z
user=> (eval z)
hey! x
y
Note that I added the do so that both expressions would be evaluated. The code in the question contained an error.
((println 'x) 'y)
First thing that would occur would be to print 'x and println returns nil, so the expression would then look like this.
(nil 'y)
nil is not a function, but it's being evaluated at the head of the list, so that's an error. Or a null pointer exception in this case.
user=> (def z '((println 'x) 'y))
#'user/z
user=> (eval z)
x
NullPointerException user/eval674 (NO_SOURCE_FILE:1)
Upvotes: 1
Reputation: 20194
Do is a macro that evaluates its args, and returns the last one. let
, fn
, for
among others contain implicit do bodies.
In your map example, the "extra nil" is the return value of the println, and it is actually the x that is extra (it is the printed output interleaved with the sequence that map returns).
Your definition of z
does not create executable objects, but lists. Lists just evaluate to themselves when used.
Do you need to evaluate expressions stored as literals?
It is easy to wrap each each one as a thunk (a function of no arguments).
user> (def z [#(println 'x) #(do 'y)])
#'user/z
We can use reduce to execute them all, and only return the last one.
user> (reduce (fn [_ e] (e)) nil z)
x
y
here x is printed, and y is returned.
If you really need to use a list with eval, you can substitute it as apropriate above ((e)
becomes (eval e)
and z gets your original definition).
Upvotes: 3