如何防止clojure函数的参数评估?

时间:2020-05-04 08:31:47

标签: clojure

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

我希望fun的输出为((+ 1 1) (+ 1 1))。我知道引用表格可以使它不被评估。但是当我在下面引用args时,

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

输出是args。我该怎么办?

2 个答案:

答案 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引用中(即此处的+函数)。