Clojure要求语法的原理解析

18

我很难理解(因此也难以记忆)这里描述的Clojure require语法:http://clojuredocs.org/clojure_core/1.3.0/clojure.core/require。它似乎既不符合直觉,也不统一。

例如,在以下示例中,为什么需要引用这个向量:

(require '[clj-json.core :as json])

相对于常规做法,这种方法有些反直觉,因为在Clojure中通常不使用引号来表示向量(列表会被引用,而向量则被视为数据)。

并且,在这种情况下,向量是未被引用的,因此具有非均匀性:

(ns xxx 
    (:require [clj-json.core :as json]))

我意识到 require 函数和 ns 宏内的 :require 使用只是在视觉上相似,但仍然存在一些奇怪的地方。

还有其他一些奇怪之处,例如我可以这样做:

(require '(clj-json.core))

但我无法做到这一点:

(require '(clj-json.core :as json))

有人可以回答这些问题吗:

  1. 在第一个例子中,为什么需要引用向量?
  2. 为什么在ns宏中它不需要被引用?
  3. 为什么列表符号不允许使用 :as

我想知道事情为什么会是这样,是因为设计时没有注意到不一致性的存在吗?


如果你还没看过的话,可以去查看一下clojure-dev列表上的这个帖子。我觉得它非常有启发性。 - Jeremy
1个回答

11
  1. 为什么第一个例子中需要引用向量?

require 是一个函数,因此你必须引用向量来防止其被评估。否则,这些符号将在当前上下文中查找,可能导致错误或意外行为。顺便说一句,我认为这不太正确:"反直觉的是,通常在Clojure中不会引用向量(列表被引用,而向量被视为数据)"。

对你来说可能有点反直觉,但引用向量(或映射或集合)并没有什么问题。当我在REPL上快速测试某些东西时,我经常这样做,不想为映射或向量中的每个关键字键入一个:,例如:

user=> '{a 1 b 2 c 3}

不是:

user=> {:a 1 :b 2 :c 3}

如果我只是想快速获取一些数据来测试某些内容,第一个方法输入起来会稍微更快一些。

  1. 为什么在ns宏中不需要将其引用起来?

宏不会评估它们的参数,它们比普通函数调用更“懒惰”,因此符号(clj-json.corejson)不需要被引用以防止评估。

  1. 为什么列表表示法不允许:as?

抱歉,我不知道这个问题的答案。

啊,我查看了require的文档并找到了答案。还有另一种支持的形式:

“以下代码将加载库clojure.zip和clojure.set,并将其简称为's'。”

(require '(clojure zip [set :as s]))

3
好的,我明白了。原文大意是:经过你的解释,我才意识到(require ['clj-json.core :as 'json])是可以工作的(使用未引用的向量),但需要进行两次引用而不是一次,这可能是为什么引用的向量更受欢迎的原因。世界只需要让人感到合理,那我就能接受它。 - Kevin
是的,我正准备编辑或评论这个例子,以为它可能会有所帮助。还有什么不明白的吗? - okonomichiyaki
为什么不允许(require '(clj-json.core :as json))这种形式呢?我猜是因为允许这种形式会使其他被接受的形式变得模糊或者其他原因... - Kevin
2
这是一个非常晚的评论,但 (require '(clj-json.core :as json)) 不被允许的可能原因是 require 表单中的列表被用作 前缀列表。因此,(require '(clj-json.core :as json)) 相当于 (require 'clj-json.core.:as 'clj-json.core.json),这是没有意义的。 - Tianxiang Xiong

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