请在 2024 年 Clojure 状态调查! 中分享您的想法。

欢迎!请参阅 关于 页面以获取有关其工作方式的一些更多信息。

0
Clojure

嗨,我开始学习 Clojure 并对以下内容感到困惑

(doc special-symbol?) 表明 "如果 s 命名为 特殊形式,则返回 true"
(doc loop) 表明 "clojure.core/loop特殊形式:评估 …"
(special-symbol? 'loop) 返回 false。

因为 (source loop) 揭示它是一个 (defmacro …,所以我怀疑文档中是否应该将 loop 称为 而不是 特殊形式

还有因为 (special-form? 'def) 返回 true,而 def 没有源,即没有定义为宏。

1 答案

+1

loop 是一个怪异的东西,它在源中定义了两次,一次在第 37 行。

;在引导过程中,我们没有 destructuring let、loop 或 fn,稍后将其重新定义。

  clojure
(def
 ^{:macro true
   :added "1.0"}
 loop (fn* loop [&form &env & decl] (cons 'loop* decl)))

你获得的文档是从 loop 的第二次定义中获取的。
loop 的第一次定义钩入了一些编译器魔法。

然后在第 4599 行

(defmacro loop
  "Evaluates the exprs in a lexical context in which the symbols in
  the binding-forms are bound to their respective init-exprs or parts
  therein. Acts as a recur target."
  {:added "1.0", :special-form true, :forms '[(loop [bindings*] exprs*)]}
  [bindings & body]
    (assert-args
      (vector? bindings) "a vector for its binding"
      (even? (count bindings)) "an even number of forms in binding vector")
    (let [db (destructure bindings)]
      (if (= db bindings)
        `(loop* ~bindings ~@body)
        (let [vs (take-nth 2 (drop 1 bindings))
              bs (take-nth 2 bindings)
              gs (map (fn [b] (if (symbol? b) b (gensym))) bs)
              bfs (reduce1 (fn [ret [b v g]]
                            (if (symbol? b)
                              (conj ret g v)
                              (conj ret g v b g)))
                          [] (map vector bs vs gs))]
          `(let ~bfs
             (loop* ~(vec (interleave gs gs))
               (let ~(vec (interleave bs gs))
                 ~@body)))))))

好吧,这很有趣。但它并没有消除我的疑惑。如果`loop`真的像文档中所述是一个特殊形式,在网站https://clojure.org/reference/special_forms,以及它的最终定义(`:special-form true`),那么为什么`(special-form? loop)`返回false呢?
可能是因为第二个def。
因为`loop`实际上不是一个特殊形式。clojure.core中定义的任何内容按照定义不是特殊形式。您可以查看特殊形式如下

```
user=> (keys clojure.lang.Compiler/specials)
(& monitor-exit case* try reify* finally loop* do letfn* if clojure.core/import* new deftype* let* fn* recur set! . var quote catch throw monitor-enter def)
```

尽管`loop`被称作特殊形式,但它是一个宏,这是其通用风格所致。以下是`let`宏的(缩略)源代码。

```
(defmacro let [bindings & body] `(let* ~(destructure bindings) ~@body))
```
注意,它几乎是一个直通到实际特殊形式`let*`的。它只是增加了解构。这正是在很多这些中的主要区别:它们在Clojure代码中解构,并调用不需要担心解构的特殊形式。
@dpsutton -- 你应该将该评论作为答案写出来,然后我们可以对此进行投票并关闭此问题。
@dpsutton 好的,所以名为 "特殊形式" 的宏是对真实特殊形式的薄包装。这很合理。
如@Sean建议,如果你将你的评论移入答案中,我会很乐意接受它。
...