简体   繁体   English

Clojure的优化工作如何工作,它在哪里?

[英]How does Clojure's optimiser work, and where is it?

I am new to Clojure, but not to lisp. 我是Clojure的新手,但不是lisp。 A few of the design decisions look strange to me - specifically requiring a vector for function parameters and explicitly requesting tail calls using recur. 一些设计决策对我来说很奇怪 - 特别是需要一个向量用于函数参数并使用recur显式请求尾调用。

Translating lists to vectors (and vice versa) is a standard operation for an optimiser. 将列表转换为向量(反之亦然)是优化器的标准操作。 Tail calls can be converted to iteration by rewriting to equivalent clojure before compiling to byte code. 通过在编译为字节代码之前重写为等效的clojure,可以将尾调用转换为迭代。 The [] and recur syntax suggest that neither of these optimisations are present in the current implementation. []和recur语法表明当前实现中都没有这些优化。

I would like a pointer to where in the implementation I can find any/all source-to-source transformation passes. 我想在什么地方在执行我能找到的任何/所有源到源变换通行证。 I don't speak Java very well so am struggling to navigate the codebase. 我不会说Java很好,所以我很难在代码库中导航。

If there isn't any optimisation before function-by-function translation to the JVM's byte code, I'd be interested in the design rationale for this. 如果在逐个函数转换为JVM的字节代码之前没有任何优化,我会对此的设计原理感兴趣。 Perhaps to achieve faster compilation? 也许是为了实现更快的编译?

Thank you. 谢谢。

There is no explicit optimizer package in the compiler code. 编译器代码中没有显式的优化器包。 Any optimizations are done "inline". 任何优化都是“内联”完成的。 Some can be enabled or disabled via compiler flags. 有些可以通过编译器标志启用或禁用。


Observe that literal vectors for function parameters are a syntactic choice how functions are represented in source code. 观察函数参数的文字向量是如何在源代码中表示函数的语法选择。 Whether they are represented as vectors or list or anything else would not affect runtime and cannot be optimized hence. 它们是否表示为向量或列表或其他任何内容都不会影响运行时,因此无法进行优化。

Regarding automatic recur , Rich Hickey explained his decision here : 关于自动recur ,Rich Hickey 在此解释了他的决定:

When speaking about general TCO, we are not just talking about recursive self-calls, but also tail calls to other functions. 在谈到一般TCO时,我们不仅讨论递归自调用,还讨论对其他函数的尾调用。 Full TCO in the latter case is not possible on the JVM at present whilst preserving Java calling conventions (ie without interpreting or inserting a trampoline etc). 后一种情况下的完整TCO目前在JVM上是不可能的,同时保留Java调用约定(即不解释或插入蹦床等)。

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, eg Scheme, which has full TCO. 虽然自我尾调用跳转很容易(毕竟,这就是recur所做的),但隐含地这样做会对那些来自的人产生错误的期望,例如具有完全TCO的Scheme。 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. 在我能做出承诺之前,我宁愿没有部分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 特别要求向量用于函数参数

Most other lisps build structures out of syntactic lists. 大多数其他lisps用语法列表构建结构。 For an associative "map" for example, you build a list of lists. 例如,对于关联的“地图”,您可以构建列表列表。 For a "vector", you make a list. 对于“矢量”,您可以列出一个列表。 For a conditional switch-like expression, you make a list of lists of lists. 对于类似条件切换的表达式,您可以列出列表列表。 Lots of lists, lots of parenthesis. 很多列表,很多括号。

Clojure has made it an obvious goal to make the syntax of lisp more readable and less redundant. Clojure明确的目标是使lisp的语法更具可读性和冗余性。 A map, set, list, vector all have their own syntax delimiters so they jump out at the eye, while also providing specific functionality that otherwise you'd have to explicitly request using a function if they were all lists. 地图,集合,列表,向量都有自己的语法分隔符,因此它们会跳出来,同时还提供特定功能,否则如果它们都是列表,则必须使用函数显式请求。 In addition to these structural primitives, other functions like cond minimize the parentheses by removing one layer of parentheses for each pair in the expression, rather than additionally wrapping each pair in yet another grouped parenthesis. 除了这些结构基元之外,其他函数(如cond通过为表达式中的每一对删除一层括号来最小化括号,而不是将另一对包装在另一个分组括号中。 This philosophy is widespread throughout the language and its core library so the code is more readable and elegant. 这种理念贯穿整个语言及其核心库,因此代码更具可读性和优雅性。

Function parameters as a vector are just part of this syntax. 作为向量的函数参数只是此语法的一部分。 It's not about whether the language can convert a list to a vector easily, it's about how the language requires the placement of function parameters in a function definition -- and it does so by explicitly requiring a vector. 它不是关于语言是否可以轻松地将列表转换为向量,而是关于语言如何需要在函数定义中放置函数参数 - 它通过明确要求向量来实现。 And in fact, you can see this clearly in the source for defn : 事实上,你可以在defn的源代码中清楚地看到这defn

https://github.com/clojure/clojure/blob/clojure-1.7.0/src/clj/clojure/core.clj#L296 https://github.com/clojure/clojure/blob/clojure-1.7.0/src/clj/clojure/core.clj#L296

It's just a requirement for how a function is written, that's all. 这只是函数编写的一个要求,就是这样。

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

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