Clojure 的优化器是如何工作的,它在哪里?
How does Clojure's optimiser work, and where is it?
我是 Clojure 的新手,但不会 lisp。一些设计决策对我来说看起来很奇怪 - 特别需要一个函数参数向量并使用 recur 明确请求尾调用。
将列表转换为向量(反之亦然)是优化器的标准操作。通过在编译为字节码之前重写为等效的 clojure,可以将尾调用转换为迭代。 [] 和 recur 语法表明这些优化都不存在于当前实现中。
我想要一个指向 implementation 我可以找到 any/all 源到源转换过程的位置的指针。我的 Java 说得不太好,所以我很难浏览代码库。
如果在逐个函数转换为 JVM 的字节代码之前没有任何优化,我会对它的设计原理感兴趣。也许是为了实现更快的编译?
谢谢。
编译器代码中没有显式优化程序包。所有优化都已完成 "inline"。有些可以通过编译器标志启用或禁用。
请注意,函数参数的文字向量是一种语法选择,是函数在源代码中的表示方式。无论它们是表示为向量还是列表还是其他任何东西都不会影响运行时间,因此无法优化。
关于自动 recur
,Rich Hickey 解释了他的决定 here:
When speaking about general TCO, we are not just talking about
recursive self-calls, but also tail calls to other functions. Full TCO
in the latter case is not possible on the JVM at present whilst
preserving Java calling conventions (i.e without interpreting or
inserting a trampoline etc).
While making self tail-calls into jumps would be easy (after all,
that's what recur does), doing so implicitly would create the wrong
expectations for those coming from, e.g. Scheme, which has full TCO.
So, instead we have an explicit recur construct.
Essentially it boils down to the difference between a mere
optimization and a semantic promise. Until I can make it a promise,
I'd rather not have partial TCO.
Some people even prefer 'recur' to the redundant restatement of the
function name. In addition, recur can enforce tail-call position.
specifically requiring a vector for function parameters
大多数其他的 lisp 构建语法列表之外的结构。例如,对于关联 "map",您构建了一个列表列表。对于 "vector",您列出一个列表。对于类似条件开关的表达式,您可以创建一个列表列表列表。很多列表,很多括号。
Clojure 已将提高 lisp 语法的可读性和冗余性作为明显的目标。地图、集合、列表、向量都有自己的语法分隔符,因此它们会引人注目,同时还提供特定的功能,否则如果它们都是列表,您必须明确请求使用函数。除了这些结构基元之外,其他函数如 cond
通过为表达式中的每一对删除一层括号来最小化括号,而不是将每一对另外包装在另一组括号中。这种哲学在整个语言及其核心库中广泛传播,因此代码更具可读性和优雅。
作为向量的函数参数只是此语法的一部分。这与语言是否可以轻松地将列表转换为向量无关,而是关于语言如何要求在函数定义中放置函数参数——它通过显式要求向量来实现。事实上,您可以在 defn
:
的源代码中清楚地看到这一点
https://github.com/clojure/clojure/blob/clojure-1.7.0/src/clj/clojure/core.clj#L296
只是要求一个函数怎么写,仅此而已
我是 Clojure 的新手,但不会 lisp。一些设计决策对我来说看起来很奇怪 - 特别需要一个函数参数向量并使用 recur 明确请求尾调用。
将列表转换为向量(反之亦然)是优化器的标准操作。通过在编译为字节码之前重写为等效的 clojure,可以将尾调用转换为迭代。 [] 和 recur 语法表明这些优化都不存在于当前实现中。
我想要一个指向 implementation 我可以找到 any/all 源到源转换过程的位置的指针。我的 Java 说得不太好,所以我很难浏览代码库。
如果在逐个函数转换为 JVM 的字节代码之前没有任何优化,我会对它的设计原理感兴趣。也许是为了实现更快的编译?
谢谢。
编译器代码中没有显式优化程序包。所有优化都已完成 "inline"。有些可以通过编译器标志启用或禁用。
请注意,函数参数的文字向量是一种语法选择,是函数在源代码中的表示方式。无论它们是表示为向量还是列表还是其他任何东西都不会影响运行时间,因此无法优化。
关于自动 recur
,Rich Hickey 解释了他的决定 here:
When speaking about general TCO, we are not just talking about recursive self-calls, but also tail calls to other functions. Full TCO in the latter case is not possible on the JVM at present whilst preserving Java calling conventions (i.e without interpreting or inserting a trampoline etc).
While making self tail-calls into jumps would be easy (after all, that's what recur does), doing so implicitly would create the wrong expectations for those coming from, e.g. Scheme, which has full TCO. So, instead we have an explicit recur construct.
Essentially it boils down to the difference between a mere optimization and a semantic promise. Until I can make it a promise, I'd rather not have partial TCO.
Some people even prefer 'recur' to the redundant restatement of the function name. In addition, recur can enforce tail-call position.
specifically requiring a vector for function parameters
大多数其他的 lisp 构建语法列表之外的结构。例如,对于关联 "map",您构建了一个列表列表。对于 "vector",您列出一个列表。对于类似条件开关的表达式,您可以创建一个列表列表列表。很多列表,很多括号。
Clojure 已将提高 lisp 语法的可读性和冗余性作为明显的目标。地图、集合、列表、向量都有自己的语法分隔符,因此它们会引人注目,同时还提供特定的功能,否则如果它们都是列表,您必须明确请求使用函数。除了这些结构基元之外,其他函数如 cond
通过为表达式中的每一对删除一层括号来最小化括号,而不是将每一对另外包装在另一组括号中。这种哲学在整个语言及其核心库中广泛传播,因此代码更具可读性和优雅。
作为向量的函数参数只是此语法的一部分。这与语言是否可以轻松地将列表转换为向量无关,而是关于语言如何要求在函数定义中放置函数参数——它通过显式要求向量来实现。事实上,您可以在 defn
:
https://github.com/clojure/clojure/blob/clojure-1.7.0/src/clj/clojure/core.clj#L296
只是要求一个函数怎么写,仅此而已