我是Clojure的新手,但不是lisp。一些设计决策对我来说很奇怪 - 特别需要一个矢量用于函数参数,并使用recur明确请求尾调用。
将列表转换为向量(反之亦然)是优化器的标准操作。通过在编译为字节代码之前重写为等效的clojure,可以将尾调用转换为迭代。 []和recur语法表明当前实现中都没有这些优化。
我想指向implementation中我可以找到任何/所有源到源转换过程的位置的指针。我不会说Java很好,所以我很难在代码库中导航。
如果在逐个函数转换为JVM的字节代码之前没有任何优化,我会对此的设计原理感兴趣。也许是为了实现更快的编译?
谢谢。
答案 0 :(得分:6)
编译器代码中没有明确的优化器包。任何优化都是“内联”完成的。有些可以通过编译器标志启用或禁用。
观察函数参数的文字向量是如何在源代码中表示函数的语法选择。它们是表示为向量还是列表或其他任何内容都不会影响运行时,因此无法进行优化。
关于自动recur
,Rich Hickey解释了他的决定here:
在谈到一般TCO时,我们不只是在讨论 递归自调用,但也调用其他函数。完整的TCO 在后一种情况下,目前在JVM上是不可能的 保留Java调用约定(即没有解释或 插入蹦床等)。
虽然自我尾调用跳跃很容易(毕竟, 这就是recur所做的事情,隐含地这样做会造成错误 对来自的人的期望,例如方案,具有完整的TCO。 所以,我们有一个明确的重复构造。
基本上它归结为仅仅是一个区别 优化和语义承诺。直到我能做出承诺, 我宁愿没有部分TCO。
有些人甚至更喜欢'重复'来冗余重述 功能名称。此外,复发可以强制执行尾部呼叫位置。
答案 1 :(得分:1)
特别要求函数参数的向量
大多数其他lisps用语法列表构建结构。对于关联"地图"例如,您构建一个列表列表。对于"向量",您可以列出一个列表。对于类似条件切换的表达式,您可以列出列表列表。很多列表,很多括号。
Clojure明确的目标是使lisp的语法更具可读性和冗余性。地图,集合,列表,向量都有自己的语法分隔符,因此它们会突然出现,同时还提供特定的功能,否则您必须使用函数显式请求它们(如果它们都是列表)。除了这些结构基元之外,其他函数(如cond
)通过为表达式中的每一对删除一层括号来最小化括号,而不是将另一对包装在另一个分组括号中。这种理念在整个语言及其核心库中都很普遍,因此代码更具可读性和优雅性。
作为向量的函数参数只是此语法的一部分。它不是关于语言是否可以轻松地将列表转换为向量,而是关于语言如何需要在函数定义中放置函数参数 - 并且它通过明确要求向量来实现。事实上,您可以在defn
:
https://github.com/clojure/clojure/blob/clojure-1.7.0/src/clj/clojure/core.clj#L296
这只是对函数编写方式的要求,而这一切都是。