Clojure何时需要在向量之前加上撇号?

12

来自《Clojure 乐趣》一书:

第一个例子:

(def fifth (comp first rest rest rest rest))
(fifth [1 2 3 4 5])
;=> e

第二个例子:

(defn fnth [n]
  (apply comp
    (cons first
      (take (dec n) (repeat rest)))))
((fnth 5) '[a b c d e])
;=> e
为什么在第二个例子中(但不是在第一个例子中),我需要一个撇号?如果没有撇号,第二个例子将会引发错误。
2个回答

11
在第二个示例中,您需要使用撇号来防止对向量元素进行评估。如果移除撇号,Clojure 将尝试将符号 a、b 等解析为它们绑定到某些值一样。
示例:
user> '[a b c d e]
;; => [a b c d e]
user> [a b c d e]
CompilerException java.lang.RuntimeException: Unable to resolve symbol: a
user> (let [a 1
            b 2
            c 3
            d 4
            e 5]
        [a b c d e])
;; => [1 2 3 4 5]
请注意,您不必在数字前使用撇号,因为它们会自动转换为本身。
user> 1
;; => 1
user> 2
;; => 2
user> [1 2 3]
;; => [1 2 3]

在Clojure中,当符号没有绑定时,Clojure会搜索与该符号绑定的值:

user> x
CompilerException java.lang.RuntimeException: Unable to resolve symbol: x

因此,了解这一信息以及函数的参数在进入函数之前被评估的事实,就应该清楚何时何地在向量之前使用撇号。


3
在第二个例子中,引号' 的作用是防止求值器在解析该向量后继续进行求值。
其中的符号不是自我求值的(您可以在此处阅读更多信息:http://clojure.org/evaluation),求值器会尝试解析它们。
例如:
(def foo 42)

[foo]
=> [42] ;; vector with number 42, resolved via foo

'[foo]
=> [foo] ;; vector with the symbol foo, decoupled from the var foo

您可能想在这里阅读另一个引用的例子http://clojure.org/special_forms#quote,并深入了解阅读器和语法引用:http://clojure.org/reader


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接