(defn fun
[& args]
(println args))
(fun (+ 1 1) (+ 1 1))
我希望fun
的输出为((+ 1 1) (+ 1 1))
。我知道引用表格可以使它不被评估。但是当我在下面引用args
时,
(defn fun
[& args]
(println 'args))
输出是args
。我该怎么办?
答案 0 :(得分:2)
Clojure与所有非惰性语言(几乎是所有非惰性语言)一样,在调用函数之前先评估函数调用的参数。致电时:
(foo (+ 1 1) (+ 1 1))
首先评估参数
(foo 2 2)
然后调用该函数,因此在您的foo
中,args
是(2 2)
。与产生这些值的表单没有联系。
如果要阻止评估,则需要在评估之前引用 。 e。以您的呼叫方式:
(defn foo [& args]
(println args))
(foo '(+ 1 1) '(+ 1 1))
答案 1 :(得分:1)
当有多个需要引用的arg时,有时有用的一个技巧是将所有内容包装在向量中,以避免避免分别引用每个arg。考虑:
(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
))
有结果
-------------------------------
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)]
我们看到我们只需要引用包装矢量,而不是包装中的每个项目。这也表明单引号是(quote ...)
特殊形式的阅读器快捷方式。
最后一个示例显示我们可以使用语法引号(即反引号)。与此处的x
一样,它允许我们将值插入模板。由于它是为宏设计的,因此它将名称空间添加到所有Var引用中(即此处的+
函数)。