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行

;在引导过程中,我们没有解构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-from true`),那么为什么 `(special-form? loop)` 返回 false 呢?
很可能是由于第二个定义。
因为 `loop` 并非实际上是一个特殊形式。在 clojure.core 中定义的任何内容都不是特殊形式。你可以看到特殊形式列表是这样的:

```
用户=> (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 -- 你应该把这个评论作为一个答案写出来,然后我们可以给它投票并关闭这个问题。
by
@dpsutton 好的,所以名为“特殊形式”的宏是对真实特殊形式的薄封装。这很有意义。
如@Sean建议,如果你把你评论移动到一个回答中,我会很高兴接受它。
...