41

我对 Clojure 还很陌生,我不确定我是否完全理解 Clojure 中撇号和反引号之间的区别。

(def x 5)

;; Question 1
(+ x x)  ;; evaluates to 10
'(+ x x) ;; evaluates to (+ x x)
`(+ x x) ;; evaluates to (clojure.core/+ user/x user/x)

;; Question 2
`(~+ ~x ~x) ;; evaluates to (#<core$_PLUS_ clojure.core$_PLUS_@32ee28a9> 5 5)
  1. 如果我错了,请纠正我,但在我看来,撇号阻止所有符号(即 + 和 x)解析为它们各自的 var,而反引号允许符号解析为它们的 var(但不计算值在 var 内)。这是准确的吗?
  2. 不带引号的符号 (~) 到底是做什么的?是否将 var 评估为其实际值(即函数对象的 + 符号和数字对象的 x 符号)?如果您可以根据 Clojure 的 READ-COMPILE-EVAL 阶段来解释这一点,那也会很有帮助。
4

2 回答 2

39

当您使用 引用集合时',符号名称将在您输入时被引用。

'(+ x x) 
=> (+ x x)
(map namespace *1)
=> (nil nil nil)
'(bingo/+ lara/y user/z)
=> (bingo/+ lara/y user/z)
(map namespace *1)
=> ("bingo" "lara" "user")

当您使用反引号引用集合时,它会尝试查找每个符号的名称空间。如果找不到,则使用当前命名空间。如果您指定命名空间,它的工作方式'与使用限定命名空间相同。

`(+ x x)
= > (clojure.core/+ user/x user/x)
(map namespace *1)
=> ("clojure.core" "user" "user")

当您在表单~内部使用时`,将简单地不加引号。这有助于构建宏,其中宏使用定义它的命名空间中的符号以及使用它的命名空间中的符号。

 `(+ ~'x x)
 => (clojure.core/+ x user/x)
 `(+ ~x x)
 => (clojure.core/+ 3 user/x)

最后,您可以取消引用一整套引用的东西拼接。

 `(+ ~@`(x x))
 => (clojure.core/+ user/x user/x)

看到这两个xes 都可以作为命名空间限定符号列表传递,并且会被拼接到另一个列表中。您不能使用~~@在反引号引用的集合之外使用。

于 2013-07-23T12:36:33.923 回答
2

反引号是 Clojure 术语中的语法引用,请参阅http://clojure.org/reader中的描述。

在阅读过程中,`(~+ ~x ~x) 扩展为生成可以引用词法环境的列表的形式。然后编译器编译这段代码。让我们看看 `(~+ ~x ~x) 扩展成什么,在它前面加上一个引号:

user=> '`(~+ ~x ~x)
(clojure.core/seq (clojure.core/concat (clojure.core/list +) (clojure.core/list x) (clojure.core/list x)))

如果你只是在文本编辑器中插入这个表单而不是`(~+ ~x ~x),它将用+函数和两个x构建列表。因此,`(~+ ~x ~x) 扩展为构建特定结构列表的 Clojure 代码。

反引号是 Clojure 数据(列表、数组等)的一种模板语言。

于 2013-07-23T03:56:10.807 回答