【问题标题】:Clojure backtick expansionClojure 反引号扩展
【发布时间】:2014-10-31 09:29:22
【问题描述】:

根据 Learning Clojure wikibook 反引号扩展如下

`(x1 x2 x3 ... xn)

被解释为意味着

(clojure.core/seq (clojure.core/concat |x1| |x2| |x3| ... |xn|))

为什么用 seq 包裹 concat?有什么区别?

【问题讨论】:

    标签: macros clojure backticks


    【解决方案1】:

    不管它是如何产生的

    • concat 返回一个序列,并且
    • seq 返回一个与其序列参数内容相同的序列,

    ...所以seq实际上是concat上的一个身份操作... 除了在一种情况下

    s 为空序列时,(seq s)nil

    我怀疑扩展是正确的,因为

    `()
    

    ... 计算结果为

    ()
    

    ... 有类型

    clojure.lang.PersistentList$EmptyList
    

    (seq (concat))
    

    ... 计算结果为

    nil
    

    这表明对seq 的包装调用不存在。

    【讨论】:

    • 这不是真的。保留空列表:github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/… - 对 seq 的调用在那里。一切都结束了。
    • @LeonGrapentin 据我所知,我的回答是正确的,您已经确认了。我的观点是提议的扩展是错误的。正如您所说,保留空列表。我同意:它在我的答案中 - 作为一个明确的例子。 如果问题或@Chiron's answer 中的扩展占上风,它们就不会存在。我不知道这在编译器中是如何发生的。查看您引用的代码,结果是RT.cons(LIST,null)。这可能会返回 null,但我们知道它不会。
    • 查看第 837 行以上的所有其他情况 - 以及第 837 行的其他情况 - 它们都包装了一个以 seq 开头的列表。这就是它在阅读器中发生的方式。
    • @LeonGrapenthin 尽管如此,由于上述原因,提议的扩展是无效的。 答案中实际出了什么问题
    • 建议的扩展是正确的。 ``()` 被读作(),因为它有一个例外。在所有其他情况下,seq 被包装。
    【解决方案2】:

    严格来说,它扩展为:

    (macroexpand '`(x1 x2 x3))
    (clojure.core/seq (clojure.core/concat (clojure.core/list (quote user/x1)) (clojure.core/list    (quote user/x2)) (clojure.core/list (quote user/x3))))
    
    (macroexpand `(x1 x2 x3))
    (user/x1 user/x2 user/x3)
    

    为什么打电话给seq?因为序列是 Clojure 哲学中的基石。我建议你阅读Clojure Sequences。否则,我会在这里复制它。

    【讨论】:

    • 这里对macroexpand 的调用完全没用。 '`(x1 x2 x3) 的计算结果相同。
    • @amalloy 确实是的。我只是在这里发布更多解释。如果你建议我可以删除它。
    • 这甚至没有回答一点问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-21
    • 1970-01-01
    • 2013-03-29
    • 2017-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多