问题 Clojure中let和let *之间的区别


考虑以下宏:

(defmacro somemacro []
    (list 'let ['somevar "Value"] 'somevar))

扩展它会产生以下结果:

(macroexpand '(somemacro))

结果:

(let* [somevar "Value"] somevar)

我有两个关于let *(带星号)的问题:

  • 这是什么意思? (特别是:它在某处记录了吗?)
  • 为什么宏没有随着'正常'而扩展? (即,没有星号。)两者产生相同的结果(在我的实验中)。有反例吗?

不幸的是,我找不到关于let *的任何“官方”文档,这就是我在这里问的原因。

我已经考虑过的来源:

(doc let*)  ; --> nil
(source let*)  ; --> source not found
  1. https://clojuredocs.org/clojure.core   - >我看到不要*在这里 (虽然有例如清单*)
  2. https://clojuredocs.org/clojure.core/let  - >只提到过一次 评论,这对我来说并不完全清楚:

    Nota Bene:让Clojure就像让我们在Scheme中一样 - 每个init-expr都可以访问前面的绑定表单。 (还有一个let *,但它或多或少都没有解构,实际上是底层实现。)

  3. Common Lisp中的LET与LET * - >这个问题是关于常见的lisp,但也许它在Clojure中是一样的?
  4. 这个答案: https://stackoverflow.com/a/5084339/3398271

    在Clojure中,它基本上意味着“foo *就像foo,但有些不同,你可能想要foo”。换句话说,这意味着该代码的作者无法为第二个函数提供更好的名称,因此他们只是在它上面打了一个星。

- >这是let和let *的情况吗?但如果是这样,问题仍然存在,究竟是什么区别呢?

  1. Scheme中let和let *有什么区别?  - >这在Clojure中是一样的吗?

6315
2017-07-27 19:01


起源

显然还有一个 if 和 if* 对。和。一样 let,文档不容易找到。我不知道 if结构,所以必须继续下去。 - Reb.Cabin
@ Reb.Cabin,有趣。同 if* 没有记录它可能是内部的,不适合消费。我在GitHub上查看了Clojure源代码,但GitHub的搜索被删除了 * 出。有很多案例 if。我想答案是在本地下载源并运行 grep 本地。 - Shannon Severance


答案:


let* 是一个内部实现细节。 let 是一个实现的宏 let*https://github.com/clojure/clojure/blob/clojure-1.7.0/src/clj/clojure/core.clj#L4301

let 添加参数 解构 至 let*。这是标准模式 xyz 和 xyz* 在Clojure,与 * 版本没有记录。一个例外是 list 和 list*


14
2017-07-27 19:42



谢谢你的解释,我试了一下,事实上 (let [[a b c & d :as e] [1 2 3 4 5 6 7]] [a b c d e]) 工作,而 (let* [[a b c & d :as e] [1 2 3 4 5 6 7]] [a b c d e]) 导致CompilerException。 - Attilio
我可能不太清楚。 let* 没有解构。该 let 宏调用 let*,在此过程中提供解构。 - Shannon Severance
是的,我完全理解它(我的意思是,我发现了一个证明这一点的例子:))抱歉这个混乱。 - Attilio


我以为我会补充说明原因 macroexpand 回报 let* 代替 let 可以在。中找到 的文件 macroexpand

在表单上反复调用macroexpand-1,直到它不再存在   代表一个宏形式,然后返回它。

所以会发生什么是第一次打电话 macroexpand-1 回报 (let [somevar "Value"] somevar),第二个扩展 let 成 let*

确实,

user=> (println (clojure.string/join "\n" (take 3 (iterate macroexpand-1 '(somemacro)))))
(somemacro)
(let [somevar "Value"] somevar)
(let* [somevar "Value"] somevar)
nil

如果你在宏中使用解构,输出会更有趣:

user=> (defmacro destructuring-macro [] `(let [[x y z] [:x :y :z]] y))
#'user/destructuring-macro

user=> (println (clojure.string/join "\n" (take 3 (iterate macroexpand-1 '(destructuring-macro)))))
(destructuring-macro)
(clojure.core/let [[testing.core/x testing.core/y testing.core/z] [:x :y :z]] testing.core/y)
(let* [vec__8356 [:x :y :z] x (clojure.core/nth vec__8356 0 nil) y (clojure.core/nth vec__8356 1 nil) z (clojure.core/nth vec__8356 2 nil)] testing.core/y)
nil

请注意 let 语法引用完全限定,因为它不是一种特殊的形式(即使它的文档说它是)。基本的特殊形式是 let*,语法引用不完全限定。


1
2018-03-14 21:54