请在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 呢?
by
很可能由于第二个定义。
by
因为实际上`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代码中进行解构,并调用不需要担心解构的特殊形式。
by
@dpsutton -- 你应该将这条评论写成答案,然后我们就可以给它点赞并关闭这个问题。
by
@dpsutton 好的,所以被称为“特殊形式”的宏是真正特殊形式的薄包装。这很有道理。
正如@Sean建议的那样,如果你把你的评论移到答案里,我乐于接受。
...