Clojure 与其他 Lisps

我的问题的目的是 没有开始一场口水战,而不是决定在什么情况下每种语言是“最好的工具的工作。”

我读过几本关于 Clojure 的书(编程 Clojure实用 ClojureClojure 的快乐Clojure 在行动的 Manning Early Access 版本) ,我认为它是一种很棒的语言。我目前正在阅读 放过 Lambda,它主要处理 Common Lisp 宏,而且它也是一种非常有趣的语言。

我是 没有的 Lisp 专家(更像是一个新手) ,但是这个语言家族和函数式编程一样让我着迷。

Clojure 的优点 (以及“ other”的缺点) :

  • 在 JVM 上运行。

    • JVM 是一个非常稳定、高性能的语言环境,非常符合 Sun 的“写一次,[几乎]在任何地方运行”的梦想。我可以在我的 Macbook Pro 上编写代码,将其编译成可执行的 JAR 文件,然后在 Linux 和 Microsoft Windows 上运行它,几乎不需要额外的测试。

    • (Hotspot 等) JVM 支持高质量的垃圾收集和高性能的即时编译和优化。就在几年前,我用 C 编写了所有需要快速运行的代码,现在我毫不犹豫地用 Java 编写。

    • 标准的,简单的,多线程模型。 Common Lisp 有标准的多线程包吗?

    • 使用 []{}#{}打破了所有这些括号的单调性,尽管 Common Lisp 专家可能会告诉我,使用 reader 宏,可以将它们添加到 CL 中。

Clojure 的缺点 :

  • 在 JVM 上运行。
    • 没有尾递归或延续。 Common Lisp 支持延续吗? Scheme 需要两者的支持,我相信。

其他的优点(特别是 Common Lisp) (和 Clojure 的缺点) :

  • 用户可定义读取器宏。

  • 其他优势?

有什么想法,其他的不同吗?

45051 次浏览

An important difference between Clojure and Common Lisp is that Clojure is more prescriptive about functional programming. Clojure's philosophy, idioms, and to some degree language/libraries strongly encourage and sometimes insist that you program in a functional way (no side effects, no mutable state).

Common Lisp definitely supports functional programming, but it also allows mutable state and imperative programming.

Of course, there are a number of benefits to functional programming, in the area of concurrency and otherwise. But all else being equal, it is also good to have the choice of which approach you want to use for each situation. Clojure doesn't completely prohibit imperative programming, but it is less accommodating of that style than Common Lisp.

My personal list of reasons for preferring Clojure to other Lisps (p.s. I still think all Lisps are great!):

  • Runs on the JVM - hence gets automatic access to the fantastic engineering in the JVM itself (advanced garbage collection algorithms, HotSpot JIT optimisation etc.)

  • Very good Java interoperability - provides compatibility with the huge range of libraries in the Java/JVM language ecosystem. I have used Clojure as a "glue" language to connect different Java libraries with good effect. As I also develop a lot of Java code it is helpful for me that Clojure integrates well with Java tooling (e.g. I use Maven, Eclipse with Counterclockwise plugin for my Clojure development)

  • Nice syntax for vectors [1 2 3], maps {:bob 10, :jane 15} and sets #{"a" "b" "c"} - I consider these pretty essential tools for modern programming (in addition to lists of course!)

  • I personally like the use of square brackets for binding forms: e.g. (defn foo [a b] (+ a b)) - I think it makes code a bit clearer to read.

  • Emphasis on lazy, functional programming with persistent, immutable data structures - in particular all the core Clojure library is designed to support this by default

  • Excellent STM implementation for multi-core concurrency. I believe Clojure has the best concurrency story of any language at the moment (see this video for more elaboration by Rich Hickey himself)

  • It's a Lisp-1 (like Scheme), which I personally prefer (I think in a functional language it makes sense to keep functions and data in the same namespace)

Here's a good video with a comparison of Scheme (Racket mostly) and Clojure.

To be fair, Racket has syntax sugar (additional reader stuff) for data types too (#hash, #, square brackets, etc.)

Plus, Clojure's only way to make a proper tail call is to use recur, that's the downside of compiling to JVM.

Note that recur is the only non-stack-consuming looping construct in Clojure. There is no tail-call optimization and the use of self-calls for looping of unknown bounds is discouraged. recur is functional and its use in tail-position is verified by the compiler. (Special Forms).

Keep in mind that Clojure is a language and an implementation (usually on the JVM). Common Lisp is a language with more than ten different implementations. So we have a category mismatch right here. You might for example compare Clojure with SBCL.

Generally:

  • a version of Common Lisp runs on the JVM: ABCL

  • most other Common Lisp implementation don't

  • most CL implementations have multitasking capabilities, a library provides a common interface

  • Common Lisp has syntax for arrays. Syntax for other data types can be written by the user and are provided by various libraries.

  • Common Lisp supports neither tail call optimization nor continuations. Implementations provide TCO and libraries provide some form of continuations.