Clojure vs其他Lisps
我的问题的目的不是开始一场火焰战争,而是要确定在什么情况下每种语言都是“工作的最佳工具”。
我已经阅读了几本关于Clojure(Clojure 编程 , 实用Clojure , Clojure 的喜悦 ,以及Clojure在行动的Manning早期版本)的书籍,我认为这是一个很棒的语言。 我目前正在阅读主要处理Common Lispmacros的Let Over Lambda ,而且它也是一个非常有趣的语言。
我不是一个Lisp专家(更多的是一个新手),但是这个语言家族让我着迷,一般情况下函数式编程也是如此。
Clojure的优点 (和“其他”的缺点):
-
在JVM上运行。
-
JVM是一个非常稳定,高性能的语言环境,非常符合Sun的“一次编写,几乎任何地方运行”的梦想。 我可以在我的Macbook Pro上编写代码,将其编译为可执行的JAR文件,然后在Linux和Microsoft Windows上运行,只需进行一些额外的testing即可。
-
(Hotspot和其他)JVM支持高质量的垃圾收集和非常高效的即时编译和优化。 就在几年前,我写了所有必须在C中快速运行的东西,现在我毫不犹豫地用Java来做。
-
标准,简单,multithreading模型。 Common Lisp是否有一个标准的multithreading包?
-
虽然Common Lisp专家可能会告诉我,使用读取器macros,您可以将它们添加到CL中,以
[]
,{}
和#{}
分解所有括号中的单调。
-
Clojure的缺点 :
- 在JVM上运行。
- 没有尾recursion或延续。 Common Lisp支持连续性吗? 我相信计划需要两方面的支持。
其他人的优点(特别是Common Lisp) (和Clojure的缺点):
-
用户可定义的阅读器macros。
-
其他优点?
思考? 其他区别?
我个人喜欢将Clojure添加到其他Lisp的原因列表(我仍然认为所有的Lisp都很棒!):
-
在JVM上运行 – 因此可以自动访问JVM本身的奇妙工程(高级垃圾收集algorithm,HotSpot JIT优化等)
-
非常好的Java互操作性 – 提供了与Java / JVM语言生态系统中大量库的兼容性。 我已经使用Clojure作为“胶水”语言来连接不同的Java库,效果很好。 由于我还开发了大量的Java代码,因此Clojure与Java工具很好地集成在一起(例如,我使用Maven,Eclipse和逆时针插件,用于我的Clojure开发)
-
很好的语法向量
[1 2 3]
,maps{:bob 10, :jane 15}
并设置#{"a" "b" "c"}
– 我认为这些非常重要的现代编程工具课程!) -
我个人喜欢使用方括号来绑定表单:例如
(defn foo [ab] (+ ab))
– 我认为它使代码更清晰一些。 -
强调懒惰的函数式编程,使用持久的,不可变的数据结构 – 尤其是所有核心的Clojure库都被devise为默认支持这个
-
出色的STM实现多核并发。 我相信Clojure目前拥有任何语言的最佳并发故事(请参阅Rich Hickey自己的更详细的video )
-
这是一个Lisp-1(就像Scheme),我个人比较喜欢(我认为在一个函数式语言中,保持函数和数据在同一个名字空间中是有意义的)
Clojure和Common Lisp之间的一个重要区别是Clojure对函数式编程更具说明性。 Clojure的哲学,成语以及某种程度上的语言/图书馆强烈地鼓励,有时候坚持认为你是以一种function性的方式编程(没有副作用,没有可变的状态)。
Common Lisp绝对支持函数式编程,但它也允许可变状态和命令式编程。
当然,函数式编程在并发和其他方面也有许多好处。 但是其他条件都是平等的,你也可以select你想要在每种情况下使用哪种方法。 Clojure并不完全禁止命令式编程,但与Common Lisp相比,它不太适应这种风格。
请记住,Clojure是一种语言和实现(通常在JVM上)。 Common Lisp是一种具有十多种不同实现的语言。 所以我们在这里有一个类别不匹配。 你可能会比较Clojure与SBCL。
通常:
-
Common Lisp的一个版本在JVM上运行:ABCL
-
大多数其他的Common Lisp实现都没有
-
大多数CL实现具有多任务function,库提供了一个通用接口
-
Common Lisp具有数组的语法。 其他数据types的语法可以由用户编写,并由各种库提供。
-
Common Lisp既不支持尾部呼叫优化,也不支持延续。 实施提供TCO和图书馆提供某种forms的延续。
这里有一个比较好的video(主要是球拍)和Clojure 。
公平的说,Racket也有数据types的语法糖(附加的阅读器)(#hash,#,方括号等)
另外,Clojure唯一的方法就是使用recur
,这是编译到JVM的缺点。
请注意,
recur
是Clojure中唯一的非堆栈消耗循环构造。 没有尾部呼叫优化,不鼓励使用自呼叫来循环未知边界。recur
是function性的,它在尾部位置的使用由编译器validation。 ( 特殊表格 )。