gpt4 book ai didi

types - 为什么 Clojure 变量 arity args 会根据用途获得不同的类型?

转载 作者:行者123 更新时间:2023-12-03 22:29:55 25 4
gpt4 key购买 nike

在回答 another question我在 Clojure 的可变参数函数 args 中遇到了一些我没想到的东西:

user=> (defn wtf [& more] (println (type more)) :ok)
#'user/wtf

;; 1)
user=> (wtf 1 2 3 4)
clojure.lang.ArraySeq
:ok

;; 2)
user=> (let [x (wtf 1 2 3 4)] x)
clojure.lang.ArraySeq
:ok

;; 3)
user=> (def x (wtf 1 2 3 4))
clojure.lang.PersistentVector$ChunkedSeq
#'user/x
user=> x
:ok

为什么是类型 ArraySeq在 1) 和 2) 中,但 PersistentVector$ChunkedSeq在 3)?

最佳答案

简短回答:这是 Clojure 的一个模糊的实现细节。该语言唯一保证的是可变参数函数的剩余参数将作为 clojure.lang.ISeq 的实例传递。 , 或 nil如果没有其他参数。你应该相应地编码。

长答案:它与函数调用是编译还是简单评估有关。无需详细讨论评估和编译之间的区别,只要知道 Clojure 代码被解析为 AST 就足够了。根据上下文,可以直接评估 AST 中的表达式(类似于解释),或者可以编译成 Java 字节码作为动态生成类的一部分。后者发生的典型情况是在 lambda 表达式的主体中,它将评估为实现 IFn 的动态生成类的实例。界面。见Clojure documentation有关评估的更详细说明。

绝大多数情况下,编译代码和评估代码之间的差异对您的程序来说是不可见的;它们的行为方式完全相同。这是编译和评估导致行为略有不同的罕见极端情况之一。不过,重要的是要指出,这两种行为都是正确的,因为它们符合语言所做的 promise 。

Clojure 代码中的函数调用被解析为 InvokeExpr 的实例在 clojure.lang.Compiler .如果正在编译代码,则编译器会发出字节码,该字节码将调用 invoke IFn 上的方法使用适当的数量( Compiler.java, line 3650 )的对象。如果代码只是被评估而不是编译,那么函数参数被捆绑在一个 PersistentVector 中。并传递给 applyTo IFn 上的方法对象(Compiler.java, line 3553)。

具有可变参数列表的 Clojure 函数被编译为 clojure.lang.RestFn 的子类。类(class)。该类实现了IFn的所有方法,收集参数,并发送到适当的 doInvoke arity。您可以在 applyTo 的实现中看到也就是说,在需要 0 个参数的情况下(就像您的 wtf 函数中的情况),输入 seq 被传递给 doInvoke方法并且对函数实现可见。 invoke 的 4 参数版本同时,将参数捆绑在 ArraySeq 中并将其传递给 doInvoke方法,所以现在您的代码会看到 ArraySeq .

更复杂的是,Clojure 的 eval 的实现函数(这是 REPL 正在调用的函数)将在内部包装一个正在评估的列表表单(一个匿名的、无参数的函数),然后编译并执行该 thunk。所以几乎所有的调用都使用了对 invoke 的编译调用。方法,而不是由编译器直接解释。 def 有一个特殊情况无需编译即可显式评估代码的表单,这说明了您在那里看到的不同行为。
clojure.core/apply的执行也调用applyTo方法,并通过这个逻辑传递给 apply 的任何列表类型应该看到函数体。确实:

user=> (apply wtf [1 2 3 4])
clojure.lang.PersistentVector$ChunkedSeq
:ok

user=> (apply wtf (list 1 2 3 4))
clojure.lang.PersistentList
:ok

关于types - 为什么 Clojure 变量 arity args 会根据用途获得不同的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26042835/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com