简体   繁体   English

Clojure中let和let *之间的区别

[英]Difference between let and let* in Clojure

Consider the following macro: 考虑以下宏:

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

Expanding it yields the following result: 扩展它会产生以下结果:

(macroexpand '(somemacro))

Result: 结果:

(let* [somevar "Value"] somevar)

I have two questions about let* (with the asterisk): 我有两个关于let *(带星号)的问题:

  • What does it mean? 这是什么意思? (In particular: is it documented somewhere?) (特别是:它是否在某处记录?)
  • Why is the macro not expanded with the 'normal' let? 为什么宏没有随着'正常'而扩展? (Ie, let without the asterisk.) Both yield the same result (in my experimentation). (即,没有星号。)两者产生相同的结果(在我的实验中)。 Is there a counter example? 有反例吗?

Unluckily I could not find any 'official' documentation about let*, that's why I'm asking here. 不幸的是,我找不到关于let *的任何“官方”文档,这就是我在这里问的原因。

Sources I've already considered: 我已经考虑过的来源:

(doc let*)  ; --> nil
(source let*)  ; --> source not found
  1. https://clojuredocs.org/clojure.core --> I see not let* here (although there is eg list*) https://clojuredocs.org/clojure.core - >我看到不让*在这里(虽然有例如列表*)
  2. https://clojuredocs.org/clojure.core/let --> only mentioned once in a comment, that is not totally clear to me: https://clojuredocs.org/clojure.core/let - >在评论中只提到过一次,这对我来说并不完全清楚:

    Nota Bene: let in Clojure is like let* in Scheme -- each init-expr has access to the preceding binding forms. Nota Bene:让Clojure就像让我们在Scheme中一样 - 每个init-expr都可以访问前面的绑定表单。 (There is also a let*, but it is more or less let without destructuring, and in fact is the underlying implementation.) (还有一个let *,但它或多或少都没有解构,实际上是底层实现。)

  3. LET versus LET* in Common Lisp --> this question is about common lisp, but maybe it's the same in Clojure? 在Common Lisp中LET与LET * - >这个问题是关于常见的lisp,但也许它在Clojure中是一样的?
  4. This answer: https://stackoverflow.com/a/5084339/3398271 这个答案: https//stackoverflow.com/a/5084339/3398271

    In Clojure it basically means "foo* is like foo, but somehow different, and you probably want foo". 在Clojure中,它基本上意味着“foo *就像foo,但有些不同,你可能想要foo”。 In other words, it means that the author of that code couldn't come up with a better name for the second function, so they just slapped a star on it. 换句话说,这意味着该代码的作者无法为第二个函数提供更好的名称,因此他们只是在它上面打了一个星。

--> Is this the case for let and let*? - >这是let和let *的情况吗? But if so, still the question remains, what is exactly the difference? 但如果是这样,问题仍然存在,究竟有什么区别?

  1. What is the difference between let and let* in Scheme? Scheme中let和let *有什么区别? --> Is this the same in Clojure? - >这在Clojure中是一样的吗?

let* is an internal implementation detail. let*是一个内部实现细节。 let is a macro implemented in terms of let* . let是一个用let*实现的宏。 https://github.com/clojure/clojure/blob/clojure-1.7.0/src/clj/clojure/core.clj#L4301 https://github.com/clojure/clojure/blob/clojure-1.7.0/src/clj/clojure/core.clj#L4301

The macro let adds parameter destructuring to let* . let添加参数解构 let* This is the standard pattern for xyz and xyz* in Clojure, with the * version not being documented. 这是Clojure中xyzxyz*的标准模式, *版本没有记录。 An exception being list and list* . listlist*是一个例外。

I thought I would add that the reason why macroexpand returns let* instead of let can be found in the documentation of macroexpand : 我想我会补充说macroexpand返回let*而不是let可以在macroexpand文档中macroexpand

Repeatedly calls macroexpand-1 on form until it no longer represents a macro form, then returns it. 在窗体上重复调用macroexpand-1,直到它不再表示宏窗体,然后返回它。

So what happens is the first call of macroexpand-1 returns (let [somevar "Value"] somevar) , and the second expands let into let* . 所以会发生什么是第一次调用macroexpand-1的回报(let [somevar "Value"] somevar)第二膨胀letlet*

Indeed, 确实,

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

If you were to use destructuring in your macro, the output would be more interesting: 如果你在宏中使用解构,输出会更有趣:

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

Notice that let is fully qualified by the syntax quote, because it is not a special form (even though its documentation says it is). 请注意, let完全由语法引用限定,因为它不是一种特殊形式(即使它的文档说明了它)。 The underlying special form is let* , which is not fully qualified by the syntax quote. 底层的特殊形式是let* ,它没有完全由语法引用限定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM