uu dd
uu dd

Reputation: 541

How to prevent the evaluation of arguments of clojure function?

(defn fun
  [& args]
  (println args))
(fun (+ 1 1) (+ 1 1))

I want the output of fun to be ((+ 1 1) (+ 1 1)). I know quoting a form can make it unevaluated. But when I quote args as below,

(defn fun
  [& args]
  (println 'args))

the output is args, though. How can I do this?

Upvotes: 2

Views: 602

Answers (2)

Alan Thompson
Alan Thompson

Reputation: 29984

One trick that is sometimes handy when there is more than one arg that needs quoting is to wrap everything in a vector, so as to avoid quoting each arg separately. Consider:

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test) )

(defn foo
  [args]  ; not rest args. no `&` present!
  (spyx args))

(dotest
  (foo (quote [(+ 1 2) (+ 3 4)])) ; sometimes this is easier to read & manipulate
  (foo '[(+ 1 2) (+ 3 4)]) ; this is a reader shortcut for the above
  (let [x 4]
    (foo `[(+ 1 2) (+ 3 ~x)]) ; backquote is handy, and always fully-qualifies Var names
  ))

with result

-------------------------------
   Clojure 1.10.1    Java 14
-------------------------------

Testing tst.demo.core
args => [(+ 1 2) (+ 3 4)]
args => [(+ 1 2) (+ 3 4)]
args => [(clojure.core/+ 1 2) (clojure.core/+ 3 4)]

We see we only need to quote the wrapping vector, not each item inside it. This also shows that the single-quote is a reader shortcut for the (quote ...) special form.

The last example shows that we may use the syntax-quote (i.e. backquote). It allows us to insert values into a template as with x here. Since it is designed for macros, it adds the namespace to all Var references (i.e. the + function here).

Upvotes: 1

Svante
Svante

Reputation: 51551

Clojure, like all non-lazy languages (which are almost all), evaluates arguments to a function call before calling the function. When you call:

(foo (+ 1 1) (+ 1 1))

first the arguments are evaluated

(foo 2 2)

then the function is called, so in your foo, args is (2 2). There is no connection to the forms that produced those values.

If you want to prevent evaluation, you need to quote before evaluation, i. e. in your calling form:

(defn foo [& args]
  (println args))

(foo '(+ 1 1) '(+ 1 1))

Upvotes: 3

Related Questions