Clojure中let和let *之间的区别

时间:2015-07-27 19:01:10

标签: clojure

考虑以下宏:

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

展开它会产生以下结果:

(macroexpand '(somemacro))

结果:

(let* [somevar "Value"] somevar)

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

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

不幸的是我找不到任何官员'关于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. LET versus LET* in Common Lisp - >这个问题是关于常见的口齿不清,但在Clojure中它可能是相同的吗?
  4. 这个回答:https://stackoverflow.com/a/5084339/3398271
      

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

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

    1. What is the difference between let and let* in Scheme? - >这在Clojure中是一样的吗?

2 个答案:

答案 0 :(得分:17)

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

let将参数destructuring添加到let*。这是Clojure中xyzxyz*的标准模式,*版本没有记录。 listlist*例外。

答案 1 :(得分:1)

我想我会在documentation of macroexpand中找到macroexpand返回let*而不是let的原因:

  

在窗体上反复调用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*,它没有完全通过语法引用限定。